AS3013 Computational Astrophysics - St Andrews Astronomy [PDF]

12 Jun 2006 - 7.5.2 Xemacs and Kate . ...... and type rm -r test. • exit This closes the current terminal you are usin

19 downloads 16 Views 278KB Size

Recommend Stories


Astronomy Astrophysics
It always seems impossible until it is done. Nelson Mandela

Astronomy Astrophysics
In every community, there is work to be done. In every nation, there are wounds to heal. In every heart,

Astronomy Astrophysics
We may have all come on different ships, but we're in the same boat now. M.L.King

Astronomy Astrophysics
We can't help everyone, but everyone can help someone. Ronald Reagan

Astronomy Astrophysics
You're not going to master the rest of your life in one day. Just relax. Master the day. Than just keep

Astronomy Astrophysics
We may have all come on different ships, but we're in the same boat now. M.L.King

Astronomy Astrophysics
I tried to make sense of the Four Books, until love arrived, and it all became a single syllable. Yunus

Astronomy Astrophysics
Don't count the days, make the days count. Muhammad Ali

Astronomy Astrophysics
You can never cross the ocean unless you have the courage to lose sight of the shore. Andrè Gide

Astronomy & Astrophysics
What you seek is seeking you. Rumi

Idea Transcript


AS3013 Computational Astrophysics Colin Simpson Thomas Robitaille March 7, 2008

1

CONTENTS

2

Contents 1 Foreword

5

2 Useful Internet Sources

5

3 Programming

5

4 Making Your First Program

6

5 Simple Programs 5.1 A Simple Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Example Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

7 7 8

6 Source Code 6.1 Source Code Layout 6.2 Upper/Lower Case . 6.3 Ampersand . . . . . 6.4 Comments . . . . . . 6.5 Colour . . . . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

9 . 9 . 9 . 9 . 10 . 10

7 Terminal and Compiling 7.1 Connecting to a Linux or Unix machine 7.2 The Command Lline . . . . . . . . . . . 7.2.1 Opening a Terminal . . . . . . . 7.2.2 Commands . . . . . . . . . . . . 7.3 A Short Example . . . . . . . . . . . . . 7.3.1 More Commands . . . . . . . . . 7.3.2 Batch Processing . . . . . . . . . 7.4 Where Files are Kept . . . . . . . . . . . 7.5 Editing Files . . . . . . . . . . . . . . . 7.5.1 Pico . . . . . . . . . . . . . . . . 7.5.2 Xemacs and Kate . . . . . . . . . 7.6 Setting Up A .cshrc.extras File . . . . . 7.7 Compiling . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . . . . . . . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

10 10 10 10 11 12 12 13 13 14 14 14 14 15

8 Print and Read 16 8.1 Print Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 8.2 Read Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 8.3 Points of Interest . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 9 Variables and Data Types 9.1 What is a Variable? . . 9.2 Declaring Variables . . . 9.3 Variable Types . . . . . 9.3.1 Integer . . . . . . 9.3.2 Real . . . . . . . 9.3.3 Double Precision 9.3.4 Character . . . . 9.3.5 Logical . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

17 17 17 18 18 18 18 19 19

10 Operators 10.1 Simple Arithmetic . . . . . . 10.2 Simple Maths Functions . . . 10.3 Mixing Variable Types . . . . 10.4 Fixing Mixed Variable Types

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

19 19 20 20 21

. . . . . . . .

. . . . . . . .

CONTENTS

11 Debugging 11.1 Bugs . . . . . . . . . . . . 11.2 Compiler Provided Errors 11.3 Run-Time Errors . . . . . 11.4 Hidden Bugs . . . . . . . 11.5 Common Bugs . . . . . . 11.6 Debugging Tricks . . . . .

3

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

21 22 22 22 23 23 25

12 If Commands 12.1 What is an If Command? . . . . . . . . 12.2 ’If’ Statement . . . . . . . . . . . . . . . 12.3 ’If-Then’ Command . . . . . . . . . . . 12.4 ’If-Then-Else’ Command . . . . . . . . . 12.5 ’If-Then-ElseIf-Else’ Command . . . . . 12.6 ’If’ Conditions . . . . . . . . . . . . . . 12.7 Variable Types and Tolerance . . . . . . 12.8 Nested ’If’ Commands . . . . . . . . . . 12.9 Points of Interest . . . . . . . . . . . . . 12.9.1 Indenting . . . . . . . . . . . . . 12.9.2 Calculations Inside If Commands

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

. . . . . . . . . . .

25 25 26 26 27 27 28 29 29 30 30 30

13 Do-Loops 13.1 Bowling Example . . . . . . . . . 13.2 ’Range’ of Do-Loops . . . . . . . 13.3 Using the ’Range’ in Calculations 13.4 Endless Do-Loops . . . . . . . . . 13.5 Do While Loops . . . . . . . . . 13.6 Nested Do-Loops . . . . . . . . . 13.7 Points of Interest . . . . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

. . . . . . .

30 30 30 31 31 32 33 33

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Using Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

. . . . . . . . .

34 34 34 35 35 36 36 37 37 38

. . . . . .

. . . . . .

14 Arrays 14.1 What is an Array? . . . . . . 14.2 Simple Use of Arrays . . . . . 14.3 Declaring Arrays . . . . . . . 14.4 Inputting Data to Arrays . . 14.5 Array Dimension Declerations 14.6 Parameter Command . . . . . 14.7 Matrices . . . . . . . . . . . . 14.7.1 Implied Do-Loop . . . 14.8 Allocatable Arrays . . . . . .

. . . . . .

15 External Input/Output Files 15.1 Reading in .DAT Files . . . . . 15.2 Creating .DAT Files . . . . . . 15.3 Writing Data to External Files 15.4 Using Text Files to Fill In Read

. . . . . .

. . . . . .

. . . . . . .

. . . . . .

. . . . . . .

. . . . . .

. . . . . . .

. . . . . . .

. . . . . . . . . . . . . . . . . . . . . Commands

16 Functions and Subroutines 16.1 Functions . . . . . . . . . . . . . . 16.2 Subroutines . . . . . . . . . . . . . 16.2.1 More Complex Subroutines 16.2.2 Arrays in Subroutines . . . 16.3 Points of Interest . . . . . . . . . . 16.3.1 Variable Types . . . . . . . 16.3.2 Same Variable Names . . . 16.3.3 Intent Command . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

. . . .

38 38 40 40 40

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

. . . . . . . .

40 41 43 45 45 45 45 45 46

CONTENTS

4

17 Modules 17.1 Creating Modules . . . . . . . . . 17.2 Linking Programs and Modules . 17.2.1 Linking in Source Code . 17.2.2 Linking in Command Line 17.3 Selective Module Usage . . . . . 17.4 Additional Info . . . . . . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

46 46 47 47 48 49 49

18 Some Useful Commands 18.1 Pause Command . . . . . . . 18.2 Dot Product Command . . . 18.3 Matmul Command . . . . . . 18.4 Random Numbers . . . . . . 18.5 More Mathematical Functions

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

49 49 50 50 51 51

19 Plotting Packages 19.1 PGPLOT . . . . . . . . . . . . . . 19.1.1 Basic Operation . . . . . . 19.1.2 PGBEG . . . . . . . . . . . 19.1.3 PGENV . . . . . . . . . . . 19.1.4 PGPOINT . . . . . . . . . 19.1.5 PGLINE . . . . . . . . . . . 19.1.6 PGLAB . . . . . . . . . . . 19.1.7 PGEND . . . . . . . . . . . 19.1.8 A Useful Source . . . . . . 19.2 GNUPLOT . . . . . . . . . . . . . 19.2.1 Getting started . . . . . . . 19.2.2 Specifying columns to plot . 19.2.3 Specifying window ranges . 19.2.4 Specifying labels . . . . . . 19.2.5 Log-Log plots . . . . . . . . 19.2.6 Lines and dots . . . . . . . 19.2.7 Saving your plot . . . . . . 19.3 SUPERMONGO . . . . . . . . . . 19.3.1 Getting started . . . . . . . 19.4 EXAMPLES . . . . . . . . . . . . 19.4.1 PGPLOT . . . . . . . . . . 19.4.2 GNUPLOT . . . . . . . . . 19.4.3 SUPERMONGO . . . . . . 19.5 Converting Postscript Files . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

51 51 52 52 53 53 54 54 55 55 55 55 55 56 56 56 56 56 57 57 58 58 59 59 59

Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

59 60 60 60

20 Your Own Personal 20.1 g95 . . . . . . . . 20.2 Salford . . . . . . 20.3 Memory Sticks . 21 Closing Words

. . . . .

. . . . .

61

1

1

FOREWORD

5

Foreword

This is intended to be an introductory teaching booklet for FORTRAN95 for use in the AS3013 module. It covers everything you should need to start coding in Fortran and I suggest you start coding as soon as possible, since this is the best way to learn programming. However, it might also be a good idea to spend some time reading up to section 11. I have tried to make the notes as readable and clear as I can, so hopefully they will be a useful tool for learning and a good reference material in years to come. You should use some of the internet sources listed in the next section, as there are many other tutorials freely available on the internet. If you want a Fortran compiler for Windows, please look at section 20.2 at the back. If you have Mac OS X or Linux, you can get the same compiler as is used on the computers in the lab, which is called g95. You may want a compiler on your own computer to try out some of the many sample programs included in this tutorial, or to do the coding for this course on your own computer.

2

Useful Internet Sources

Here is a link to what I consider to be an excellent tutorial which starts from the very basics: http://www.cs.mtu.edu/ shene/COURSES/cs201/NOTES/fortran.html Another useful one, perhaps slightly more advanced: http://www.pcc.qub.ac.uk/tec/courses/f77tof90/stu-notes/f77tof90-stu.html The following website has a good deal of useful information on intrinsic functions: http://www.nsc.liu.se/ boein/f77to90/a5.html

3

Programming

To start with, let’s look at what we should be thinking about when programming: 1. Determine the problem: • What does the program need to do? 2. Split up the problem: • Can the program be split up into smaller subtasks? 3. Design an algorithm to solve the problem: • Keep it as simple as possible - just make it work. 4. Turn this algorithm into code 5. Debug and optimize the code: • Fix the bugs that prevent running your program. • Choose good data to feed into your program and see what goes wrong, where it goes wrong and why (though hopefully nothing will go wrong). • Choose bad data to feed into your program and see how it copes. Update your program so it can cope with bad data (not always necessary, but a very good habit). • Add suitable comments and descriptions to your program, helping you and others to follow your code. • Make the code as user-friendly as you can.

4

4

MAKING YOUR FIRST PROGRAM

6

Making Your First Program

Here is a step by step guide to making your first Fortran program on the Linux machines. 1. Login : To log into the linux computers you just need to put your username and then password into the linux computer. If there is a problem with this, you will need to find a demonstrator or Ian Taylor to try and sort it out. 2. Opening the Terminal : You should now be faced with the start-up screen on the linux computer. On the bottom of the screen you will see some symbols on the left-hand side. At the very left is a decorated K character. This acts like the Start button on Windows. Click the symbol directly to the right of the K, which looks like a blue window with an arrow in it. Click on this once and a Terminal will open. You will be using a Terminal to compile and run your programs, so you will need to open it each time you log on to the computer. 3. Sourcing g95 on Terminal : On the terminal you should see text of the form [username@machine]$ This will have a highlighted cursor to the right of it and when you type, what you type should appear there. In order to use the Fortran compiler you will need to write the following two commands into the terminal, pressing enter/return after each one: [username@machine]$ source /star/etc/login [username@machine]$ source /star/etc/cshrc 4. Opening Kate : Try typing kate into the terminal and pressing enter. This will open the kate text editor which you can write your programs in. 5. Creating your Program : It is in this text editor that you shall be putting your source code i.e. your program. I suggest copying the following ’Hello World’ program into the text editor: program first print *, "hello world" end program first 6. Saving your Program : You should now save your completed program by clicking the save as. . . button. When the box asking where you want to save to comes up, you should be located in a directory that looks similar to: /home/edge/ccs2. Now click the new folder button and call it something like compastro, but keep it in lower case and with no spaces. Once this is done save your program under the name first.f90 into this new folder. Don’t forget the .f90 extension! 7. Finding your Program using Terminal : You can now minimise the kate text editor and bring up the terminal again. Type in the following command into the terminal and press enter: cd compastro. Now type in the command and press enter: ls. You should see the name of the program, first.f90. If you don’t see it there ask for help. 8. Compiling your Program : Now having used using the cd command on terminal, you are located in the correct directory so are ready to compile and run your program. To compile the program input the following command into the terminal: g95 first.f90 -o first. This will create an executable file called first which is used to run your program. 9. Running your program : Your program is now ready to run so input the following command into the terminal: ./first. You should then get Hello World! being printed to the terminal screen. Well done - you have just created your first program! In the next few sections we shall go through the above steps in a lot more detail. If you are feeling a bit more adventurous, you can try changing the above program to do more exciting things than just printing a line of text. However, you now know the very basic principles of creating and running a program.

5

SIMPLE PROGRAMS

5

7

Simple Programs

The programs given in this section are very basic, comprising just a few commands and have only one main body. The lines of text which make up the program are called the source code and this what you will write into the text editor.

5.1

A Simple Example

Presented here is the source code for a program to add up and also multiply two numbers and print the two separate results to the screen. This is source code so should be written into the text editor. 1. As good programming practice, the first lines of source code should include, as comments, the programmers name, the purpose of the program, the date it was created/modified, any problems/bugs it has and whatever else seems appropriate. Comments are started by a ! character as follows: ! ! ! ! !

Program written by Colin Simpson ([email protected]) Purpose: demonstrates the making of a program Created: 12 June 06 Last Modified: Feb 08 Problem: Has no known bugs/problems

2. The first line of the program commands must be started with program followed by the name of the program: program maths Typically the name of your program isn’t important, but you want to choose sensible names. It doesn’t need to share the name of the saved file, however none of the variables in your code should share the same name as the program name. 3. The second line should simply be implicit none if you are using variables. A variable can be thought of just now as a box, used by the computer to store a piece of information, which is given a name to identify it. For example the value of π might be stored in a variable/box called pi. This variable can then be accessed, used and adapted throughout the program. program maths implicit none 4. Next you need to declare your variables if you have any. In this program we need two integer variables alpha and beta: program maths implicit none integer :: alpha , beta If you don’t understand that line fully just now, it will be explained in more detail later. 5. Next you need enter any desired starting values for your variables. So let’s say I have alpha = 2 and beta = 3: program maths implicit none integer :: alpha , beta alpha = 2 beta = 3

5

SIMPLE PROGRAMS

8

6. Next you will want to make use of the computing power at your disposal. The purpose of this program is simply to add and separately multiply two integer numbers together, and then print the answers to the Terminal screen: program maths implicit none integer :: alpha , beta alpha = 2 beta = 3 print *, "alpha + beta = " , alpha + beta print *, "alpha * beta = " , alpha * beta 7. At the end of your source code, you need to put end program: program maths implicit none integer :: alpha , beta alpha = 2 beta = 3 print *, "alpha + beta = " , alpha + beta print *, "alpha * beta = " , alpha * beta end program maths There you go! That’s the source code for a simple program. You will later be guided through how all these commands work in a fair amount of depth, this is just to give you a feel for what a program looks like. With your source code complete, the next step is now to compile and run the program using the Terminal.

5.2

Example Programs

Here are a few more example programs. They are pretty basic and should be pretty intuitive, even if some of the commands are new to you. Try copying these programs into your text editor, one program per file, and then compiling and running them like you did in section 4. program example1 implicit none real :: alpha , beta , charlie print *, "please enter values for alpha and beta: " read *, alpha , beta charlie = alpha * beta print *, "the value of alpha multiplied by beta is: " , charlie charlie = charlie * 2.0 print *, "twice that value is: ’ , charlie end program example1 program example2 implicit none integer :: i , x print *, "the first five terms in 2x for x=1,2... are: " do i =1,5 x = i * 2 print *, x end do end program example2

6

SOURCE CODE

9

program example3 implicit none real :: alpha print *, "please enter a real value for alpha:" read *, alpha if (alpha .eq. 2.0) then print *, "you entered 2.0" else print *, "you didnt enter 2.0" end if end program example3

6

Source Code

You will put your source code as any number of lines of text into a text editor. A text editor is simply a piece of software that makes it easy for you to write nice, well laid out and readable source code. I would suggest using either the editors kate or xemacs. You will write the source code for each program into a separate file and save this file into your compastro folder, complete with the .f90 extension added to the end of the name of the file. Many new programmers will often not pay much attention to how their source code looks, but simply want it to work. Although getting your program to work might seem a first priority, keeping well laid out and readable source code helps make it easier for you to fix your program when things go wrong. Here then are some tips on source code.

6.1

Source Code Layout

Each line of code should be less than about 80 characters in length if possible since this will make reading the code easier. Most text editors should have a column number displayed somewhere. Blank spaces and lines throughout the source code, also known as white space, will not affect its execution so should be used to make the code readable. Don’t squash everything together, space it out. Certain commands blocks such as if blocks and do blocks should be indented appropriately since they have a logical structure to them.

6.2

Upper/Lower Case

Fortran does not distinguish between upper and lower case letters so it is possible to adopt different layouts. Some people prefer to have intrinsic commands in capital letters with the rest of the source code as lower case: PROGRAM uppercase IMPLICIT NONE REAL :: alpha, beta Some people prefer to have everything in lower case. The choice is up to you, just try to be consistent throughout.

6.3

Ampersand

Some of your source code lines will be in excess of 80 characters, in which case you may want to put a single line on two lines to keep it easily readable. To split a single line of source code over two lines, simply finish the line before the next, and start that line itself, with an ampersand & :

7

TERMINAL AND COMPILING

10

If this were executable code then & & I have just spread this one statement across two lines

6.4

Comments

A comment starts to the right of where you place the ! character: program implicit none

! this command begins a program ! this magical fortran command should never be forgotten

Comments are not interpreted as code, so are simply for the aid of the person reading the source code. They can be placed anywhere in the lines of the program. Anything that is placed to the left of a ! will not be included as a comment and will be interpreted as code. Comments should be used to explain the actions of what the code is doing, though they should be brief as well. Though for simple programs they can seem to be stating the obvious, they will become very useful once your source code becomes more complex.

6.5

Colour

Syntax Highlighting is the name given to when your text editor colours in different commands in different colours. For example , your comments might come up as grey, most of the rest of the code in black with some special commands coming up as blue. The colours depend on the text editor you are using and is simply to make the source code more readable. It is possible that in some cases the text editor will not support syntax highlighting of some commands. This does not mean that the compiler will not recognise that it is a command, but just that the text editor hasn’t recognised it. As such, the command should still work if spelt and used correctly, so don’t panic. Run your program and see if it is flagged up as an error. Here is a short list of commands not supported by syntax highlighting deallocate

7

Terminal and Compiling

This section focuses on use of the Terminal, which you be will using to perform a variety of tasks, including compiling and running your programs.

7.1

Connecting to a Linux or Unix machine

The first step is to log on to a linux computer in the computer lab. To do this, simply enter your ITS username and password, and you will be logged in to the K Desktop Environment (KDE).

7.2 7.2.1

The Command Lline Opening a Terminal

This may be the first time you use a Linux or Unix system. Instead of performing tasks graphically, you will now spend a lot of your time performing simple tasks (such as copying, deleting, and moving files) using what we call a command line i.e. typing in commands rather than using the mouse. Although this may seem like a step backwards technologically, don’t be fooled! - it is actually more powerful because commands are much more flexible. For example I can easily delete all files which end in .dat, start with the letter p, and contain the number 8 somewhere in the middle. This is not something you can easily do graphically, especially if you are in a folder with thousands of files! To open a new terminal (a window where you type in commands), follow these steps:

7

TERMINAL AND COMPILING

11

Linux machines Click on the icon on the bar at the bottom of the screen which looks like a little dark screen/window with a ’>’ symbol. Windows machines You should see a little window waiting for you to type a command. Type xterm & to open a terminal.

7.2.2

Commands

You are now ready to use the command line! You should see something like [username@machine]$ or [username@machine]% in the terminal at the beginning of the line. We call this a prompt because the computer is waiting for you to type in a command. Once you have typed a command, press the enter/return key to send the command to the computer. For the purposes of this lab you will need access to a Fortran compiler and other tools. You will need to type the following commands in order to have access to them (Note: do not type in [username@machine]$, but only what comes after) [username@machine]$ source /star/etc/login [username@machine]$ source /star/etc/cshrc Although command-line may be new to you, the way files are stored is more or less identical to that of a normal Mac or PC, in that you can have folders, and files or folders within these folders. In this section I will list a few useful commands that you will need to start with. Commands are usually case sensitive. For example the LS command may have a different effect to the lower case ls. And always be very careful when using the command line, if you misuse the rm command for example you might end up deleting all your files! The basic commands you will need are: • ls lists all the files and folders in the current folder (list contents). Type it, and you should see something like this: [username@machine]$ ls document.txt mail work As with any UNIX command, you can add ‘options’ to commands. For example ls -l lists all the files and folders, but with some extra info (e.g. size, date modified, etc...). [username@machine]$ ls -l total 0 -rw-r--r-1 tom tom drwxr-xr-x 2 tom tom drwxr-xr-x 2 tom tom

2399 Feb 68 Feb 68 Feb

9 11:55 document.txt 9 11:55 mail 9 11:55 work

• man is a life-saving command which gives you a help page about any command you may wish to use, and the options you can use with it. For example, you could type man ls to see some information on how to use the ls command, and what the different options do (for example -l which we used above). Use the arrow keys to move up and down, and press q to quit. Don’t hesitate to use the man command! • pwd tells you what directory you are in at the moment (print working directory) • mkdir folder creates a folder (make directory)

7

TERMINAL AND COMPILING

12

• cd folder moves you to the folder you want to go to (change directory). There are several ways you can use this. You can either type in a ‘relative’ path, which is the folder you want to go to relative to where you are at the moment. Or you can enter an absolute path, which is the path from the ‘root’ of the disk, denoted by a /, which is the folder which contains everything on the computer. See Section 7.3 for an example of this. Typing cd on its own returns you to your home directory.

7.3

A Short Example

Examples speak better than words, so consider the following example which uses what we have just learned. (anything after the # is just my comments). Don’t hesitate to type these commands yourself at the same time - I have not included any ’dangerous’ commands. [username@machine]$ pwd # What directory are we in? /home/purds/username/ # This is the absolute path to this directory [username@machine]$ ls # What is in this directory? document.txt mail work # There are three files/folders [username@machine]$ ls -l # I need more information total 0 -rw-r--r-1 tom tom 100 Feb 9 11:55 document.txt drwxr-xr-x 2 tom tom 68 Feb 9 11:55 mail drwxr-xr-x 2 tom tom 68 Feb 9 11:55 work # document.txt is a file and the mail and work are directories # (note the ‘d’ at the beginning of the line which indicates directories) [username@machine]$ mkdir test [username@machine]$ ls -l total 0 -rw-r--r-1 tom tom drwxr-xr-x 2 tom tom drwxr-xr-x 2 tom tom drwxr-xr-x 2 tom tom

# Create a new directory called test # I can check that it is there 100 68 68 68

Feb Feb Feb Feb

9 9 9 9

11:55 11:55 12:06 11:55

document.txt mail test # Here it is! work

# I now want to move to this directory (‘moving down’). I can type it two ways: [username@machine]$ cd test # relative path [username@machine]$ cd /home/purds/username/test # absolute path [username@machine]$ pwd /home/purds/username/test

# check what directory I am in

# I now want to move out of this directory (‘moving up’). I can type it two ways: [username@machine]$ cd ../ # relative path [username@machine]$ cd /home/purds/username/ # absolute path # In Unix systems .. and . are two directories which are present in all directories # . refers to the current directory. So cd . doesn’t get you very far! # .. refers to the directory one level up # If I had wanted to move up and into the work directory I could have typed [username@machine]$ cd ../work/ # relative path [username@machine]$ cd /home/purds/username/work/ # absolute path # Now I want to go back to my home directory. I can just type [username@machine]$ cd [username@machine]$ pwd # just to make sure! /home/purds/username

7.3.1

More Commands

• du -sh folder will give you the size of the directory folder and du -sh . will give you the size of the current folder you are in.

7

TERMINAL AND COMPILING

13

• mv file1 file2 will move file1 to file2. You can use this with directories, for example mv file work/file will simply move the file to the work directory without renaming it. • rm filename removes files. Unlike on MacOS or Windows, there is no such thing as a ‘Trash’ bin. Files are deleted immediately! If you want to avoid any blunders, use rm -i which always asks for confirmation before deleting files. To delete a directory, use rm -r directory, although we now enter the realm of the really dangerous commands! Use this badly and you could loose all your files! To delete the test directory we created in Section 7.3, go to your home directory and type rm -r test • exit This closes the current terminal you are using. Other commands you will find useful in future and which you should find out more about using man include cat, more, head, tail.

7.3.2

Batch Processing

What if we want to list only fortran source code files i.e. files ending with .f90? Or what if we want to delete all files ending in .out? The unix command-line makes this very easy. Two important characters which you will need for this type of commands are * and ?. The asterisk symbol * has the meaning ‘any string of characters’. So if you type *.f90 in a command, this means ‘all files and directories whose name end in .f90’. The question mark ? has the meaning ‘any character’. Therefore ???.f90 has the meaning ‘all files or directories whose name is made up of any three characters followed by .f90’. This can be used with any command. Here are a few examples: ls rm du mv ls ls

*.f90 # List all files whose name ends in .f90 *.out # Remove all files ending in .out -sh * # Show the size of all the files and directories *.f90 programs/ # Move all files whose name ends in .f90 into programs/ p????.f90 # list all files whose name is p+any 4 characters+.f90 ?.out # list all files whose name is any one character followed by .out

WARNING! these special characters have to be treated with extreme caution. For example you will probably never want to type rm -r * since this would simply erase all files and folders in the current folders. It is easier than one might think to type this command inadvertantly. For example, if you wish to type rm -r output* to delete all folders beginning with the word output, you might make a mistake and include a space, which would give rm -r output *, which means delete the output directory, and *, i.e. everything!

7.4

Where Files are Kept

When you started at this University, you were assigned a username and password, as well as some disk space (which is usually referred to as your home directory) on a server (e.g. maths, purds, referred to as your home server ). Whatever machine you connect to for this lab, you should have access to your home directory. However, you cannot hold more than 20MB in your home directory. This can be a problem once you run programs which write out large files. Therefore, a directory has been dedicated to this module, and sits on a 20GB disk (which does not mean there is 20GB free at all times!). The path to this directory is: /net/benetnasch/honsastro/AS3013/ Inside this directory there should be a directory for each user. If this is not the case, ask the lab demonstrator. If you do not wish to have to type cd /net/benetnasch/honsastro/AS3013/ each time you log in or open a new terminal, you can create a shortcut, or symbolic link to this directory:

7

TERMINAL AND COMPILING

14

[username@machine]$ cd # To make sure you are in your home directory [username@machine]$ ln -s /net/benetnasch/honsastro/AS3013/username as3013 # Replace username by your ITS username, # and as3013 by whatever you want to call the shortcut # Now if you want to access your directory on /net/benetnasch, you can type [username@machine]$ cd as3013 # whenever you are in your home directory.

7.5 7.5.1

Editing Files Pico

One of the simplest and easiest text editors is pico, but will be of limited use for writing Fortran programs so I would advise against using it for this purpose. To edit (or create) a file named myfile for example, simply type pico myfile. At the bottom of the window, a list of useful shortcuts is listed. For example Ctrl-X saves and exits the document. Just for practice, try and create a file named myfile, and just write anything in it. Then use Ctrl-X to save it and exit. You can then use the cat myfile command to view the contents of the file.

7.5.2

Xemacs and Kate

Two much more useful text editors are xemacs and kate. These two are graphical editors, which means the mouse will be useful once again, and it will be much more intuitive to perform basic tasks such as opening and saving files. To start xemacs, type xemacs, or to start kate, type kate. To create a new file in xemacs, click on open, and simply type the name of the new file you want to create. Click on OK, and if the file does not exist it will be created. In kate, simply start writing your program, then save, and you will be asked for a filename. Both of these editors have advanced features such as syntax coloring and auto-indenting - which of the two you use is a matter of preference - try the two, and then you can decide for yourself! To activate syntax coloring in xemacs, go to the options menu, and click on syntax coloring, and choose in this buffer. Then go to the options menu again, and choose save options to init file. Then click on yes. This now means that syntax coloring will always be on when you open a Fortran 90 program. If you want to automatically indent all or part of your program, select the region you want to indent, go to the F90 menu, and choose indent region. Note that whichever editor you decide to use, the filename of the program has to end in .f90 in order to benefit from the above features. The Fortran 90 compiler might also get confused if you forget the .f90 extension.

7.6

Setting Up A .cshrc.extras File

Each time you open up a terminal, the computer executes the contents of a file named .cshrc in your home directory. Its name begins with a period, so it is invisible to a normal ls. However, typing ls -a should reveal all files including hidden ones. The .cshrc file should not be modified. However, if you want to add some commands which will be run each time you open a terminal, it is possible to do so, by creating a file called .cshrc.extras To do this, go to your home directory (can be done by just typing cd on its own). Then, type the following [username@machine]$ pico .cshrc.extras to create and open this file. You will probably want to write in this file the following commands, so that you don’t have to do this every time you start a new terminal:

7

TERMINAL AND COMPILING

15

[username@machine]$ source /star/etc/login [username@machine]$ source /star/etc/cshrc Then simply press Ctrl-X to save and close pico. Now every time you open a new terminal, the g95 command should work straight away!

7.7

Compiling

A fortran program is one (or more) files containing source code, which is a sequence of commands such as: program test print *,‘Hello World!’ end program test as was described earlier. These files can be given any name ending in .f90, and can be written by any text editor you want, as long as the output is plain text (and not for example a Word file, or an rtf file). For example, the above program could be saved in a file called mycode.f90. The name after the program commands in the source code does not have to match the filename. A compiler reads in the source code and writes it out into a machine-executable file. The compiler available on the Linux machines is g95. The following command compiles the source code, i.e. it creates a file which can be executed to run your program: [username@machine]$ g95 mycode.f90 # replace mycode.f90 by whatever your source code file is called a.out is the default name given by the compiler to the executable file, but is not a very interesting name. Instead you can specify the -o option when you compile the code, in the following way, in order to give it a more explicit name: [username@machine]$ g95 mycode.f90 -o myprog # replace myprog by whatever you want to call the executable file The next step is to run the program. To do this, type the name of the executable file preceded by ./ For the above example where the file is called myprog, use [username@machine]$ ./myprog If you decided not to give the executable file a name other than a.out, then use [username@machine]$ ./a.out mycode.f90 and myprog are just examples of names you can use. In practice you could use for example question1.f90 for the source code file, and q1 for the executable file. In this case you would write your source code in question1.f90, and then run the following commands to compile and run the program: [username@machine]$ g95 question1.f90 -o q1 [username@machine]$ ./q1 Once you write more complex programs, you may choose to have the main program in a file and a subroutine in another. To compile this type of program, simply list all the .f90 files needed in the compiling command: [username@machine]$ g95 mycode.f90 subroutine.f90 -o myprog

8

PRINT AND READ

8

16

Print and Read

Now that we know how to use the terminal and compilers a bit better, let us go back to how to make programs. If your program does some amazing calculation, you want to print your results to the screen right? If you don’t, your numbers will be in the computer, but you won’t be able to see them! So like in the example programs earlier you’ll want to print the values to the screen. You might also want to get the user to put in the values they want to do calculations with. In a simple addition program, they may want to choose their own values to add together. For this purpose, we have the print and read commands (sometimes you will see the write command being used instead of print, but for now we shall use print). These commands can output numbers to the terminal screen and also read in input from buttons pressed on the keyboard or, in another scenario, take data from an external file on the computer.

8.1

Print Command

Lets first consider the simpler case of printing screen output: print * This will simply print out a blank line - pretty useful for making your output readable, where output just refers to what the user of the program will see. print *, ’some text’ This will simply print the text to the screen. The place to print to here is designated by the * which just directs the text to the screen the user is looking at. print *, ’some text’ , a This will simply print the text to the screen followed on the next line by the variable a. print *, ’some text’ , a , b This is like above, but will now print two variables a and then b on the same line. print *, a , b This is like above , but will omit the text and print just the variables. So that was pretty simple right? You will quickly get used to using print statements in all these different forms. Watch out though, don’t put something like don’t with an apostrophe in it. If you do that, fortran will think you’ve stopped printing text after don, so you will get a compiling error. So forget your school english lessons, apostrophes are bad in text!! You should check the colour of the writing to see if you are in fact printing text (it should come up a unique colour thanks to syntax highlighting). If you really want to include your apostrophes, you can enclose your desired text in ” ” (double apostrophes) instead: print *, ”what’s the point though? It’s just an apostrophe”

8.2

Read Command

Let’s move onto the case of reading values from keyboard and storing them as variables: read *, a This will simply pause the program’s execution until a number is entered and return is pressed. If return is pressed and no number was present at the time, then fortran will simply continue to wait, but will have skipped a line on the screen as you may observe, but that is nothing to worry about, it didn’t read in any values. Once a number is entered the variable a will take on that value.

9

VARIABLES AND DATA TYPES

17

read *, a , b This will simply wait until two values are entered. It will read in a first and then b.

8.3

Points of Interest

It is a good idea when reading in values to print a statement before it, asking what is wanted from the user: print *, ’please enter a value for radius:’ read *, radius If you read in a number that is declared as an integer variable, and the user puts a decimal place in their input (e.g. 13.4), you will get a run-time error so make it clear to the user they should enter an integer number. There is also the case of where you want to read in a character variable. If say the length of the variable is 10, then fortran will only accept the first 10 characters the user puts in. If you were to put in: supercalifragilisticexpialidocious, it would only store supercalif under the variable name. If you were to put in hello then fortran would store this variable as hello with 5 blank spaces added on at the end. That is the very basics of keyboard input/output. It is good to structure your program so it includes these print and read statements in a clear way to the user. Try to remember that other people will have to use your program so give them instructions as to what to put it, what not to put in etc . . .

9 9.1

Variables and Data Types What is a Variable?

When you are wanting to create a program that works out some calculation or do most tasks, you will need to declare any variables you are using. A variable is just a number, or string of letters, stored by the computer under a certain name. It might also be a logic statement as we will see in section 9.3.5.

9.2

Declaring Variables

Say you want to add two numbers c and d, then you would need to declare these as variables at the start of your program. This is done by writing the type of variable (such as integer or real ) followed by :: and then the name of the variable or variables. To assign a value to a variable c we use the assignment operator =. Let us for the following example consider the variables c and d to be integers: program add implicit none ! this is to be included if you use variables - don’t forget it integer :: c , d c = 567 d = -34 print *, ’c+d is equal to:’ , c+d end program add You can see that in the above program we have declared the two variables c and d so that we can add them together. If we do not do this then the program will not compile since it will not recognize what these variables are. Also note that you cannot enter the values of variables until all variables have been declared (see section ?? to find out the trick to assigning the value of a variable before all variables have been declared).

9

VARIABLES AND DATA TYPES

18

Numerical constants are stored fully as just numbers, so do not put commas or spaces in them. So for example don’t enter the following: 13,230 13 230

9.3

Variable Types

Here we will go through all the different variable types available in fortran. 9.3.1

Integer

Any number not containing a decimal point or exponent. integer :: a , b e.g. 13 , -5 , 234 , 0 9.3.2

Real

Any number followed by a decimal place and/or exponent: real :: c , d e.g. 0.0 , 3.141 , -76.2 , 8. , 2.01 , 7.2e4 , 2e-4 Note: The decimal point is not required if you use the exponent. 9.3.3

Double Precision

Any number written in exponent form using a d instead of the usual e : double precision :: e , f e.g. 0d0 , -13.67d0 , 7.3d6 , 4.1d-3 Note: These are very useful for cases where you need high levels of precision. Double precision makes your program work harder to get that extra accuracy, so if speed of your program is a problem, you should avoid using them. For our simple programs, that won’t be a problem, so feel free to use them and compare the results to that of a similar program which makes use of real numbers. So if in your program you want to declare a as real and b as double precision: real :: a double precision :: b If you want to declare three reals and two integers: real :: a , b , c integer :: d , e Warning : You do not want to mix different types of variables so that you have some calculations mixing the different types of expressions. It would be unwise to divide a double precision number by an integer. See a full list of consequences of mixing variable types in section 10.3. It should only be done if absolutely required and with the presence of a few useful commands to be looked at in section 10.

10

OPERATORS

9.3.4

19

Character

This is a set length of characters/letters that can be stored as a string. character(len=12) :: str1 e.g. ’hello’ , ’ ’ (just a blank) , ’astrophysics rulz’ So lets say you want to make a represent the string ’hello’ in a program. You will need to declare the variable as a character and set it’s length as follows: program hello implicit none character(len=5) :: a ! len=5 indicates the length of the string variable ’a’ to be 5 a = ’hello’ print *, a end program hello Note: You must always define the length of the string. If you were to specify here that the length was 10, then fortran would simply put ’hello’ with five spaces added on the end of that. If you set the length to 4 then only the first four characters would be used so you would print ’hell ’, which some people might not like, so remember to declare a suitable length! 9.3.5

Logical

This one will possibly seem a bit obscure for the moment and you might not get much chance to use it during the course. We can define a variable, let’s say on to be equal to the logic statement .true. We could also define off to be equal to .false. You typically would most likely use this for when you are dealing with if commands, which we shall discuss later, but I thought that I’d better include this in here: program logic implicit none logical :: on = .true. if (on) print *, ’we used a logic variable!!’ end program This is a pretty pointless example, but there are situations where you might want to use logic commands - be creative!

10

Operators

You’ll need to know what symbols represent what type of operation (such as addition, subtraction, etc...) so that you can perform calculations using fortran.

10.1

Simple Arithmetic

The simple operators are: 1 2 3 4 5 6

a a a a a a

=b +b -b *b /b ** b

represents represents represents represents represents represents

setting the value of a equal to that of b (not vice-versa) a added on to b a minus b a times b a divided by b a to the power of b

Fortran performs these operatorions in the order of following priority: 1. brackets

10

OPERATORS

20

2. exponentiation 3. multiplication and division 4. addition and subtraction Please remember to make full use of brackets, even if strictly not necessary, since it will save you valuable time looking for bugs later if you make a mistake. You will in time be able to avoid using as many brackets, but you may as well start off using lots of them just to be safe - seriously . . . use many brackets! For example, x**-1 is not allowed, but x**(-1) is. x*-1 is not allowed, but x*(-1) is. a**b**c is not the same as (a**b)**c

10.2 You 1 2 3 4 5 6

Simple Maths Functions

also have sin(a) cos(a) tan(a) asin(a) acos(a) atan(a)

a few pre-programmed maths functions. Here are some of the useful ones: represents sine of a represents cosine of a represents tangent of a represents inverse sine of a represents inverse cosine of a represents inverse tangent of a

Note that in all of the above a is in radians 1 2 3 4

log(a) log10(a) sqrt(a) abs(a)

represents represents represents represents

natural logarithm of a log to base 10 of a the square root of a the absolute value of a

Note : more complete lists are available on the internet and a useful url to such a site is given in section 2. Fortran will not like it if you have bad numbers for a - like say you try to take the log of a negative number - this falls under the idea of designing your code not to accept bad data. Don’t let it happen that a could be negative if possible, or else you will get either a run-time error or a weird end result.

10.3

Mixing Variable Types

Be wary of mixing types of variables! They can have unexpected and undesired consequences. You may want to check the online tutorial I suggested to you to get a better list of these consequences, but here are some of the more common problems: 1. You can only raise negative numbers to an integer power 2. Double precision and real numbers are allowed to be raised to integer powers and nothing bad will happen. 3. Dividing a real or double precision number by an integer will truncate the result to being an integer. 4. Some compilers don’t like you raising real and double precision numbers to real and double precision powers. etc . . . You need then to be very careful not to mix and match different variable types at random. Fortran can usually cope and return the correct results, but it’s good practice to avoid it and will save you valuable time looking for bugs later.

11

DEBUGGING

10.4

21

Fixing Mixed Variable Types

So what happens when we have no choice but to mix variable types? Well, there are a few useful commands which convert variables of one type into another type. Please note that you will not have to redeclare the variable type at the start of the program. For example, if you need an integer variable star to disguise itself as a real variable temporarily and star is declared at the start as an integer this is fine! No need to go back and redeclare it as a real as well. 1. int(a) This will return the truncated value of a in integer form. Be warned that it will not round up so int(13.9999) will return a value of 13, not 14! 2. nint(a) This will return the truncated value of a in integer form. Unlike above, it will return the rounded integer value so 13.999 -¿ 14. 3. real(a) This will return the real value of a. So real(13) will return a value of 13.00 which can potentially make all the difference. 4. dble(a) This will return the double precision value of a. So dble(13.45) will give you something like 13.45000000000 . These commands can be used on all numerical variable types, so you can use dble() on real and integer numbers for example. Let’s look at a possible example which has some random calculations mixing variable types which I have tried to fix: integer :: a double precision :: b real :: c a=4 b = 2.356d0 c = 7.1 c = real(b) / real(a) b = dble(a) + dble(c) a = int(b+c) When using these commands, you actually have to be very careful, as there can be differences in your answer depending on how you go about applying these commands. For example, int(b+c) may well not give the same answer as int(b) + int(c): integer :: a1 , a2 real :: b , c b = 14.5 c = 2.7 a1 = int(b+c) a2 = int(b) + int(c) print *, ’first value for a is:’ , a1 print *, ’second value for a is:’ , a2 In this example a1 is 17 and a2 is 16 - not the same! So you have been warned, think very carefully when using these expressions, and try not to have to mix variable expressions since they can cause a lot of trouble.

11

Debugging

Debugging is just the name given to trying to the process of trying to fix the problems in your code that either break it or stop it from operating correctly or smoothly.

11

DEBUGGING

11.1

22

Bugs

What are bugs? They are glitches in your program, problems with the code that make the program do strange things. For example, your program might work out the wrong value, not print anything at all, try to calculate infinity or just generally break! The more complex a piece of code, the more opportunities there are for errors. Debugging can be frustrating and often takes a lot of time for complex pieces of code. So how can you make your debugging easier? Well, when you start out (and even for experienced programmers) there will be a few more than likely candidates for bugs in your program. You will at first be struck clueless as to what on earth is wrong with your code, but with experience you will become familiar with some common causes of bugs.

11.2

Compiler Provided Errors

Compilers usually try and seek out the obvious bugs, so if your compiling fails then it will give you a list of problems it found. You should work your way through these and resolve the problems. It can take a bit of getting used to the error messages, they themselves sometimes seem to be in cryptic jargon, but you will get the hang of what problems they are pointing out. Each compiler has it’s own unique way of seeking out and alerting you of bugs. It takes experience more than anything else to understand what the problem is - trust me on that. So let’s say we try to compile a program which has the program command mis-spelt as progra. We would get the following terminal message: ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test In file example.f90:5 PROGRA cool\_numbers 1 Error: Unclassifiable statement at (1) So the first line is just the terminal command we used to try and compile the program with. The second line states the file, and then program line, which it has found error with - in this case the error is in file ’example.f90’ on line 5. The next line then gives a direct quote of the line in error. The last line will then give the compiler’s best guess at what the bug/error is. If you can see nothing wrong with that line, then it is entirely possible that the error is indeed not on that line! The compiler is not as smart as us, therefore it will often think it has found the root of the problem when in fact it is looking in entirely the wrong place. So don’t place complete trust in the compiler error messages, as useful as they usually are.

11.3

Run-Time Errors

You may also get run-time errors, which is just an error which occurs during the execution of your code. This may cause the program to give false answers or to stop running, neither of which are a good thing! These can often be the worst to resolve, since the compiler hasn’t picked up on the problem. In the upcoming example, my program has been compiled successfully under the executable name test. It encounters an error during run-time though, when the user is asked to enter a value for alpha. The user enters a real number, but the code is expecting alpha to be an integer - so it breaks during execution: ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ ./test enter value for alpha: 2.2 At line 10 of file example.f90 (Unit 5) Traceback: not available, compile with -ftrace=frame or -ftrace=full Fortran runtime error: Bad integer for item 1 in list input

11

DEBUGGING

11.4

23

Hidden Bugs

Your program may run without any error messages coming up but that doesn’t mean that your program is bug free. Have you checked that your answers make sense? Quite often your code will not quite do what you were expecting it to do, so you need to become alert to what the code is doing, helping that by printing your variable values at chosen intervals to see if everything is proceeding smoothly. In the upcoming example, my program is supposed to read in the radius of a circle and then print the area of that circle to the user. Unfortunately, because I was in a hurry I put the brackets in the wrong place and am using the wrong equation to calculate the area: ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ ./test enter value for radius: 3.0 area of circle = 88.8212 So it should be pretty obvious to the user that this is not correct, so obviously something has gone wrong somewhere. Although the bug is easy to recognise here, in a program using a more complicated equation the error may not be so obvious!

11.5

Common Bugs

So what are some of the most basic and seemingly silly sources of bugs: 1. Using full-stops when you should use commas and vice-versa. This seems really silly but happens all too commonly. You will normally only use full-stops in if commands so please don’t let years of English teaching influence you to use full-stops. So if the compiler points to a seemingly valid line of code, please just quickly check it has correct use of commas, etc . . . ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test In file example.f90:14 read *, i , j , a . b 1 Error: Syntax error in READ statement at (1) 2. Spelling mistakes (and all other grammatical errors) Very easy to do and can make compilers complain about what seems like valid line of code, so again just make a quick check of the spelling of variables, commands, etc . . . ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test In file example.f90:26 prin *, ’area of circle = ’, area 1 Error: Unclassifiable statement at (1) 3. Forgetting to declare a variable, or declaring it as the wrong type. Also, mixing variable types. You might forget to actually declare your variable as an integer, or whatever it is, at the start of your code. If you do you may see something like this: ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test In file example.f90:32 area = (3.1415 * radius) ** 2.0 1 Error: Symbol ’area’ at (1) has no IMPLICIT type

11

DEBUGGING

24

Or you might in your program try to declare an integer number using a = 2.0 as user input. This will not work and will break the compiler like in section 11.3. You need to enter a = 2 since it is an integer variable. 4. Dividing by zero If say you haven’t set a value for a variable (so it has a default value zero) and you try and divide by it, you will either get an error or a hidden bug, depending on what compiler you use. This happens for any divide by zero situation. In the upcoming example, my code has an equation in which gamma is equal to alpha divided by beta. I remember to declare a value to alpha but forget to assign any value to beta which assumes a default value of 0.0. Thus my result for gamma is +∞ - not ideal: ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ ./test beta = 0. gamma = +Inf This is a hidden bug when using g95, because the code still runs, but does not do the desired thing. The next bugs might not make sense to you yet, but should do if you come back to look at this again later: 1. Non-constant variable types in functions and subroutines. If your input or output variables in functions and subroutines do not match the variable types of the calling program, you will get an error. Resolve this using the conversion operators, but be wary of truncated answers, lost precision, etc . . . In the upcoming example, I have a real variable called apple in the main example, which is exchanging information with the double precision variable alpha in my subroutine called conversion one: ccs2:~/Documents/astronomy/compastro/ex2 ccs2$ g95 example.f90 -o test In file example.f90:11 call conversion_one(apple,grass , tree) 1 In file example.f90:19 SUBROUTINE conversion_one(alpha,beta , gamma) 2 Warning (155): Inconsistent types (REAL(4)/REAL(8)) in actual argument lists at (1) and (2) 2. Endless do-loops Also known as an infinite loop for the obvious reason that the code does performs the same block of code forever. This can happen pretty easily too and can be a pain to spot unless you know a good trick. 3. Segmentation Fault This one appears a lot, especially when you start making use of arrays. This can be one of the toughest bugs to solve, as g95 does not provide any explicit information as to which bit of the code is failing, but will instead just quote segmentation fault during run-time. The trick for solving this one is to look at whether or not the physical dimensions/sizes of the arrays have been declared properly. If the array is being passed between the main program and subroutines, check that the size of the array is also being passed along with it.

12

IF COMMANDS

11.6

25

Debugging Tricks

Now let’s look at some handy tricks for debugging: 1. print statements to isolate problems. If you think you are in an endless do loop or your program stops running during run-time, then a simple method to use something like this: print *, ’I am here (1)’ You can replace the ’1’ by ’2’ then ’3’ then ’4’ etc... This prints those words onto your terminal screen, so if I am here (4) doesn’t come up then you know the problem is near there. Put in as many as you want, to try and isolate the bugs, and then just delete the print statements after. 2. print numerical values to figure out why your answer is wrong. This is similar to printing ’I am here’ statements, except that you simply print numerical values every so often to see if one of the calculations has gone wrong. 3. Colour! Most text editors will provide different colours for commands, comments, etc . . . So if a comment doesn’t have the colour of a comment, maybe you forgot the ! Or perhaps in a print statement you missed out the ’ ’ surrounding the printable text, so check it has the colour in the source code that other printed text has. You will spend a lot of your programming time debugging, there is no one that won’t - so if you have a problem the most likely candidate to solve the bug is yourself. You should know the code better than anyone if you wrote it. If you’re really stuck, ask for help fom people to see if they can spot that elusive problem. Be patient.

12 12.1

If Commands What is an If Command?

If commands are used for when you want to check if variables in your program meet a certain condition. Based on whether the variable/s meets the condition or not, you can make this have an effect on other variables in, or the progress of, your program. There are an infinite number of things you could do with an if command, but let’s look at a simple example to give us a feel for it: program whatif implicit none integer :: a print *, ’please enter an integer value for a:’ read *, a if (a .eq. 2) then print *, ’you entered the number 2’ else if (a .eq. 4) then print *, ’you entered the number 4’ else print *, ’you didnt enter 2 or 4’ end if end program whatif This is a pretty intuitive example, feel free to play about with it. You will need to be told though that .eq. means equals (a full list of these is given later). If you don’t understand it though, no worries,

12

IF COMMANDS

26

just keep reading, you’ll see this example again later (or soemthing very similar to it at least) and hopefully then you’ll understand it fine.

12.2

’If ’ Statement

With if commands, there are what I consider to be different levels of if command. The first level is the simple if-statement. This is simply that if the condition supplied after the if is true then the bit of code after it on the same line is performed. If the condition is not met, then the if-statement is just ignored. To think of an example of this: program whatif implicit none integer :: a print *, ’please enter an integer value for a:’ read *, a ! if an integer is not input we get a runtime error if (a .ne. 2) a=2 ! the if-statement, where ’.ne.’ means ’does not eqaul’ print *, ’a = ’, a end program whatif In this example, we should find that the code will print out the value 2 no matter what the user inputs. This is because the condition is true when the input value is not equal to 2. So the code will perform the operation that a=2 when we did not put in the value of a to be 2. If we did input the value of a to be 2, then the if-statement is ignored. As a result, no matter what we put in, the final result is that a will be equal to 2. Pretty simple right?

12.3

’If-Then’ Command

So let’s move on to the next level of if command. This is the if-then command. If the condition supplied after the if is true, then the code will perform the block of code that comes in the lines of code after the if-then line. So it’s actually very similar to the if-statement except that we perform a block of code instead of just one line. Unlike the if-statement, we must include a line of code with just end if to signify the end of the block of code we perform if the if condition is true. An example may make this clearer: program whatif implicit none integer :: a print *, ’please enter an integer value for a:’ read *, a if (a .ne. 2) then print *, ’you know, I think you should have entered the number 2’ print *, ”so I am going to enter the number 2 into ’a’ for you” a=2 end if print *, ’a = ’ , a end program whatif This works with the same principles as the if-statement example so I won’t explain it in detail. You should note though I have indented the if-then command, this is to make it easier to read for other people (you should get into the habit of doing this).

12

IF COMMANDS

12.4

27

’If-Then-Else’ Command

The next level is the if-then-else command. This is used for when we want to perform a block of code if the condition is true, or another block of code if the condition is false. Like before, if the condition supplied is true, then the block of code after it is performed. This time though, we stop the first block of code when we reach a line including just the source code else. After this line, we then perform the block of code for when the condition is false, until we reach the end if line. Again, here is an example to make things clearer: program whatif implicit none integer :: a print *, ’please enter an integer value for a:’ read *, a if (a .ne. print *, print *, a=2 else print *, print *, a=3 end if

2) then ’you know, I think you should have entered the number 2’ ’so I am going to enter the number 2 for you’

’im impressed, number 2 is indeed a good number’ ”but just to be different I will now make ’a’ equal to 3”

print *, ’a = ’ , a end program whatif So in this example, a is in the end equal to 2 for any value of a we input, except for when we input a equal to 2, in which case we get out at the end that a is equal to 3!

12.5

’If-Then-ElseIf-Else’ Command

Right, now onto the last level, the if-then-elseif-else command. This uses the exact same principles as the previous levels, except that we have introduced our last new concept to the if command, the else if command. This basically introduces a new possible condition, so that if we want to see check to see if another condition is true, we include that new condition in an else if command. The else if command must be placed after the initial if then command and before an else command, otherwise your compiler will complain. You are also allowed to have any number of else if commands and if you don’t want to include an else command either that’s fine. One more example may be helpful: program whatif implicit none integer :: a print *, ’please enter an integer value for a:’ read *, a if (a .eq. 2) then print *, ’you entered the else if (a .eq. 4) then print *, ’you entered the else if (a .eq. 5) then print *, ’you entered the else print *, ’you didnt enter end if

number 2’ number 4’ number 5’ 2,4 or 5’

12

IF COMMANDS

28

end program whatif Remember this example? It’s almost the same one from the start, I hope you now understand it. If none of the conditions in all of the if or else if commands, then the else block will be carried out, not just if one of them is false.

12.6

’If ’ Conditions

So before we close up this chapter, we need to take a closer look at our if conditions. These are the logic statements which decide how to compare quantities to give either true or false. Here then is a list of the logic statements we can use in our arsenal of if commands: 1. .eq. equals if (a .eq. b) print *, ’a equals b’ 2. .ne. doesn’t equal if (a .ne. b) print *, ’a not equal to b’ 3. .gt. greater than if (a .gt. b) print *, ’a greater than b’ 4. .ge. greater than or equal to if (a .ge. b) print *, ’a greater than or equal to b’ 5. .lt. less than if (a .lt. b) print *, ’a less than b’ 6. .le. less than or equal to if (a .le. b) print *, ’a less than or equal to b’ We can also combine multiple conditions in one if command using the following and, or, not commands 1. .and. if (a .eq. b .and. c .eq. d) print *, ’a equals b and c equals d’ 2. .or. if (a .eq. b .or. c .eq. d) print *, ’a equals b or c equals d’ 3. .not. You may remember when we were talking about logical variable types. Well, this seems like a good place to revisit the concept. A logical value may at any time be designated a value .true. or .false. So what if we set a variable on to equal .true. and we use: if (on) then . . . We are here saying that the condition in the brackets is .true. therefore we carry out of the if block as if we had a true condition (i.e. the same as having (a .eq. b) when a = b = 2 ) You will have to be imaginative about how to use them, since I haven’t had much experience in what situations you could use them.

12

IF COMMANDS

12.7

29

Variable Types and Tolerance

We need to be careful with our variable types (we always have to be), since if say we have two real numbers a and b and apply the following if command: if (a .eq. b) then . . . We might not very often get this to be true, since they would have to match exactly down to the last decimal point. So instead you might be more wise to use: if (abs(a-b) .lt. tolerance) then . . . This basically says that if the absolute value of the difference between the two values is less than the value of the variable tolerance (which you usually want to set to be very small, like say about 1.0e-6 or something) then we consider them to be equal. With integers, they will match exactly because there are no decimals to consider, but with real and double precision numbers you need to be careful as they often will not match up exactly.

12.8

Nested ’If ’ Commands

You can also get nested if commands - basically these are if commands that are placed within another. So if for example your first logical condition is true, you might then want to place another if command block to test if another condition is true: if (a .gt. b) then if (a .lt. c) then print *, ’a is greater than b but less than c’ else if (a .gt. c) then print *, ’a is greater than both b and c’ else print *, ’a is greater than b and the same as c’ end if else if (a .gt. c) then if (a .lt. b) then print *, ’a is greater than c but less than b’ else if (a .gt. b) then print *, ’a is greater than both c and b’ else print *, ’a is greater than c and the same as b’ end if else print *, ’a is less than or equal to both b and c’ end if The above code is perhaps a bit confusing to look at, but should hopefully be intuitive to read through. Can you see how I have indented the nested if commands to make it easier to follow? You might also consider putting some blank lines in there to seperate each block. There are no bonus points for cramming you code into as few lines as possible, so please try to get into the habit of spacing things out nicely. Some comments wouldn’t go amiss either. When using nested if commands, you are allowed to use any level of if command. They could be if statements, if-then commands, etc . . . It is a good idea to run through your code, to check that the logic of your if-commands is as you want it. In the above example for example, it can be very easy to get lost and make a mistake - so take your time and it will save you effort later when you look for what went wrong with your program.

13

DO-LOOPS

12.9 12.9.1

30

Points of Interest Indenting

It should be heavily textitasised that you should indent your if commands with a couple of spaces or a tab or whatever you prefer. It is a vital habit to get into, since it will make your code a lot easier to follow and is especially important when you start to use nested if commands. 12.9.2

Calculations Inside If Commands

Don’t be afraid to do some calculations inside your if commands like in the example above. Quite often you will need to compare combinations of your variables, so if you want to do it inside your actual if commands that’s fine, just remember to make clear use of brackets. Here is a random example of two quantities you could potentially have to compare: if ( (abs(a**b)-real(c)) .ge. (real(d)*e) ) then . . .

13

Do-Loops

In your program, you quite often want to repeat a task multiple times, like say you wanted to perform ten repetitions of adding a number to a total sum. This can get very tedious if you were to write out in full all of these calculations in your program. So to make repetitive tasks easier we use do-loops.

13.1

Bowling Example

For now, let us consider the example of ten-pin bowling! There are four rows of pins, with each row having one more pin than the previous row. So we have 1 pin in row 1, 2 pins in row 2, etc. . . If we add all of these together we get 10 pins in four rows, right? What if we wanted to play with ten rows of pins, how many pins would that be? We shall use fortran to work this out, instead of adding 1+2+. . . +9+10 (which is 55 and takes about 1 second to work out in my head, but that’s not the point, this is a simple example!) program bowling integer :: i , pins integer, parameter :: rows = 10 pins = 0 do i=1,rows pins = pins + i end do print *, ’number of pins is:’ , pins end program bowling So hopefully that program should print out the answer for ’pins’ as being 55. What now if we went crazy and decided to play with 273 rows - how many pins would there be (use this piece of code to get it)? It should be 37,401 pins and fortran calculated that a lot quicker than I could. As a little exercise, you ought to try adapting this code to ask the user how many rows of pins they would like, and them tell them how many pins they need to find to play their crazy game. See what happens if they put in a negative number of rows!

13.2

’Range’ of Do-Loops

When I say range I really mean the iterative property of the do-loop. The easiest way for me to explain this is with examples so let’s look at a few ways in which the range of do-loops can be defined: do i=1,10

13

DO-LOOPS

31

This will perform the loop 10 times, with i=1, i=2, . . . , i=9, i=10 ie. will perform the do-loop in steps of 1 (the default value) do i= -5,5 This will perform the loop 11 times, with i=-5, i=-4, . . . , i=4, i=5 ie. will perform the do-loop in steps of 1 do i= 1,12,2 This will perform the loop 6 times, with i=1 , i=3, . . . , i=9, i=11 ie. will perform the do-loop in steps of 2 Note how it stops at i=11 cause it can’t go up to i=13 (outside the range) do i=-6,14,4 This will perform the loop 6 times, with i=-6, i=-2, . . . , i=10, i=14 ie. will perform the do-loop in steps of 4 do i=10,1,-1 This will perform the loop 10 times, with i=10, i=9, ... , i=2, i=1 ie. will perform the do-loop in steps of -1 It doesn’t matter what type of loop you choose, but you have to use integer numbers for defining how the do-loop will operate! Most of the time the first example is a perfectly good way of going about performing a do-loop. When using do-loops, they are unlike if commands in that you must balance out the number of do commands with end do commands. There are no do-statements, only loops.

13.3

Using the ’Range’ in Calculations

If you require the integer value i to be used in your calculations, you should think very carefully about how you should define your do-loop to give you the desired number of repetitions and the desired values of i. Let’s consider an example where I want to add real numbers together, ranging from -3.0 to 7.0 in steps of 0.5: program addition implicit none integer :: i real :: sum sum = 0.0 ! we initialize this value to be zero do i=-6,14,1 ! these numbers have to be integers sum = sum + (real(i)/2.0) end do print *, ’sum of -3 to 7 in steps of 0.5 is:’, int(sum) end program addition The answer comes out as 42. Look at this program until you fully understand how it works, and please also take note of the real() command used to help us with our mixed variables and also my use of int() to truncate the final answer to give exactly 42.

13.4

Endless Do-Loops

Do-loops do not have to go for a set number of repetitions, and can be continuous until a certain condition is met. So we might want to continue a loop until our variable a meets a certain condition. Let’s consider the example where we want our user to put in values for a until they put in a negative number. We shall use two methods to demonstrate how to do this:

13

DO-LOOPS

32

program test1 implicit none real :: a a=1.0 ! we set this initial value so as not to trigger off the ’do while’ condition print *, ’please enter a real number value for a:’ do while(a .ge. 0.0) ! we shall do this loop while this condition is *true* read *, a end do print *, ’you entered a negative number’ end program test1

program test2 implicit none real :: a print *, ’please enter a real number value for a:’ do read *, a if (a .lt. 0.0) exit end do print *, ’you entered a negative number’ end program test2 For this simple code, they both operate in exactly the same way. What if we wanted to exit the loop if the user also put in a value for a to be greater than 100? Let’s look at how we could modify program test1 (I shall leave modifying test2 up to you as an exercise): program test1 implicit none real :: a a=1.0 ! we set this initial value so as not to trigger off the ’do while’ condition print *, ’please enter a real number value for a:’ do while(a .gt. 0.0 .and. a .le. 100.0) read *, a end do print *, ’you entered a negative, or over +100, number!!’ end program test1

13.5

Do While Loops

As you hopefully already know, it is possible to exit a do-loop using an if command and a relevant threshold condition to decide whether or not you should carry on with the do-loop. There is another alternative to this and that is the do-while command, like in the example above. Let’s take a closer look: program test

13

DO-LOOPS

33

implicit none real :: a,b a = 0.0 b = 0.0 do while(a .lt. 50.0) a = a+1.0 print *, a b = b+1.0 print *, b end do end program In the above example, you would continue out the block of code between the do while and the end do until a certain condition is met, in this case we do the loop until a becomes greater than or equal to 50.0 The program will not terminate immediately when it meets the necessary condition, but will instead carry on until it reaches the end of the do loop one last time. In this way it is different to the if . . . exit command. So have a good think as to which one would be more suited since one will often be more preferred over the over.

13.6

Nested Do-Loops

Let’s say that instead of having just one do-loop, you might want another do-loop inside the first one this is called nesting do-loops and is similar to nested if commands. So let’s consider an example where we want to add up a bunch of numbers: program nested implicit none integer :: i , j real :: sum sum = 0.0 do i=1,10 do j=1,5 sum = sum + real(j) print *, sum end do sum = sum + real(i) end do print *, ’final sum is:’ , sum end program nested That is a rather simple example of a nested do-loop and shall be covered in more detail in the other notes. I shall let you figure out how it works, though please do play around with that code.

13.7

Points of Interest

You need to be ever watchful with do-loops and make sure you don’t accidentally create an infinite do-loop, whereby the program will get stuck in an endless repetition - never a good thing. That can be a fairly common cause of bugs! Note that when writing do-loops, as with if commands, it is a good idea to indent each do-loop so as to make it easier to read and follow the source code.

14

ARRAYS

14

34

Arrays

Arrays are simply lists or tables of numbers stored under single variable names. These arrays can be useful for storing results and any other values your program needs or may need in future. They have the advantage that instead of using all your values there and then during your program, you can just tuck them away in a single variable.

14.1

What is an Array?

An array then is simply a list or matrix (or table) of numbers. It might have 1000 rows and 2 columns or 2000 rows and one column or any other combination I want. They are very useful to get used to, but can often throw up subtle complexities.

14.2

Simple Use of Arrays

Imagine you want the user to enter 20 values by input to the keyboard, which you can then take and calculate the mean value of (statistics make heavy use of arrays). First you will want to declare your array as a variable, similar to what you have seen before. You do this in the following way: real, dimension(5) :: exams In this example, you have created an array of five real numbers (please note that the number that follows dimension must be an integer, since you are inputting a whole number of values) under the variable name exams. They all currently have value 0.0. Let’s say you have now entered five values into the array in the following order: 11.0, 12.0, 13.0, 14.0, 15.0 This can be done by some means like keyboard input (example to follow later). Okay, so we have this array, but what can we do with it? Well, let’s imagine that we forgot what values we’d put in after a night out drinking and this array contained your five exam scores which you’d like to be able to remember. To print to the screen your first exam result use the following: print *, exams(1) This would print the number 11.0 to the screen That’s pretty intuitive right, so if you want your third test score use: print *, exams(3) This would print the number 13.0 to the screen What if you want your sixth test score? Well, you havent got one since your array only has five values so what happens if you put: print *, exams(6) Bad things happen here! It may well print some random number it has plucked from somewhere in the computer, not good if it comes up with the number 2e-208 and you think you’ve failed the imaginary exam really badly!! It’s important to get the dimensions of your arrays correct or else you get weird results cropping up here and there. Quite often if you are using g95 and start getting values of about 1e-300 in your arrays, then it is because you are not using your arrays correctly. Warning - things can get even worse when you get the array dimensions wrong. If you are reading in values and your array size is too small, your array may well get filled up with values from some random place in your computer. You can also have the potential problem of overwriting values stored somewhere in your computer with the values in your array, so be careful!

14

ARRAYS

14.3

35

Declaring Arrays

There are a whole variety of ways that you can declare arrays so let’s explore this: Consider the possibility that for some reason which no one knows, you want your array to have five values like above, but you want to go declare the values with index values from 3 to 7: real, dimension(3:7) :: exams To get your first exam result you would need to print exams(3) - you could do this, but typically you won’t declare arrays in this way. Let’s say you don’t need real variables, but would instead like integers. Simple: integer, dimension(5) :: exams Make sure and remember to input the values in as integers, so no decimal points or anything. You’ll get a run-time error if you try putting a real number into an integer array. What if you want to store a whole table of 5 rows and 3 columns (total of 15 numbers)? Then you start getting into multi-dimensional arrays (or tables): exams(1,1) exams(1,2) exams(1,3) exams(2,1) exams(2,2) exams(2,3) exams(3,1) exams(3,2) exams(3,3) exams(4,1) exams(4,2) exams(4,3) exams(5,1) exams(5,2) exams(5,3) To declare this array we would use: real, dimension(5,3) :: exams We could call up any of these individual cells in the intuitive manner. To print the middle value there: print *, exams(3,2)

14.4

Inputting Data to Arrays

So now let’s move on to how to input data to all of these arrays. For now, we will only consider input by keyboard. More advanced uses such as reading data from files is included later. There are two obvious ways to input data to arrays using keyboard input. One of them is older (back in the day of Fortran77) but you can use either. They both do exactly the same thing: real, dimension(10) :: cars read *, cars integer :: i real, dimension(10) :: cars do i=1,10 read *, cars(i) end do So Fortran will read in the first cell, cars(1), then the second cars(2), etc . . . It will continue asking for input until eventually it has filled the entire array with values. What if you now wanted to multiply every value in cars by 2.0 to give you values that you want to put into a new array called vans? Well there are two ways of doing this, one of which you might agree is potentially a lot better: real, dimension(10) :: cars, vans

14

ARRAYS

36

integer :: i read *, cars vans = 2.0 * cars real, dimension(10) :: cars , vans integer :: i do i=1,10 read *, cars(i) vans(i) = 2.0 * cars(i) end do So what then is the difference, and what is the big deal? Though this is a simple example and perhaps doesn’t show it’s full potential, Fortran90 can process arrays as single objects which saves you having to put in extra do-loops to read in values to an array and also to perform bulk calculations on an array. Another consequence of this as we can see is that we don’t actually need do-loops to read in values for the array cars, something which had to be done in Fortran77.

14.5

Array Dimension Declerations Using Variables

Another very useful idea is that of using other variables to declare the size of an array. Let’s say you have a lot of arrays of your program, all of the same dimension/size or with integer multiple sizes (so one array is of size 20, one of 40, another of 80 etc...), then if half way through writing your program you realise you need to change the size of the arrays, it could take a long time to change every single one of them in your program. That is why we can use the following piece of code: integer, parameter :: size = 20 real, dimension(size) :: cars , vans real, dimension(2*size) :: boats real, dimension(4*size) :: helicopters In this code, if we need to change the array sizes from 20,40,80 to 30,60,120 then we can just go back and change the value of size to 30. This becomes a real time saver in complex codes and is very useful for passing array sizes between subroutines and suchlike (to be seen later).

14.6

Parameter Command

A little aside on the parameter command. It can be used to give a definite value to variables, which cannot be changed at any point during the program so is particularly useful for numerical constants such as π. It is also highly useful for declaring integer values which represent the dimensional size of an array: integer, parameter :: size = 20 real, parameter :: pi = 3.141 real, dimension(size) :: stars If you use this bit of code, you force the variable to declare the value of the variable right there. In the case of declaring size, it now allows you to declare the dimensions of relevant arrays during the variable declarations. If you didn’t use parameter you couldn’t just use: integer :: size size = 20 real, dimension(size) :: cars, vans This won’t compile because fortran won’t read in your value of size until after all the variables are declared. So you use the parameter command to get round this problem, and we can use it for any variable type, not just integers. If you use it though, please try to remember and actually assign a value to the variable, so don’t leave it like this:

14

ARRAYS

37

real, parameter :: pi

14.7

Matrices

OK, so a matrix is like a table of numbers but without any headers or writing. Sometimes it is easier to store tables of numbers as matrices (especially when reading in values from files) so let’s look at the basics. You can declare an array to have more than one ’rank’ (you can have up to seven). What does it mean to have a rank one array? It just means that we are dealing with a list, rank two represents a table, etc . . . Let’s go back to our earlier example of 5 rows and 3 columns. We can declare the variable table as: real, dimension(5,3) :: table Like we described earlier, you can replace the numbers with integer variables which makes things simpler: integer, parameter :: rows = 5 integer, parameter :: cols = 3 real, dimension(rows,cols) :: table Let’s also finally look at simple examples of how the computer reads in the numbers of a matrix. If we simply use a read array statement such as: read *, table Then we would input our values in column order, or in other words we would start in the top left of our table and then, staying in that first column, work our way down all those rows. Once finished with the first column, we move to the second column and go back to the top row and repeat the process. So you would enter the values for table in the following order: table(1,1) , table(2,1) , table(3,1) , table(4,1) , table(5,1) , table(1,2) , table(2,2) etc . . . 14.7.1

Implied Do-Loop

What if we would rather enter our values in row order: ie. table(1,1) , table(1,2) , table(1,3) , table(2,1) , table(2,2) , table(2,3) etc . . . To do this, we can simply use an implied do-loop. Look at the following piece of code and you will hopefully see how it works: program implied implicit none integer, parameter :: rows = 5 integer, parameter :: cols = 3 integer :: i , j real, dimension(rows,cols) :: table do i=1,rows read *, (table(i,j) , j=1,cols) ! here is the implied do-loop bit end do do i=1,rows print *, (table(i,j) , j=1,cols) ! here is the implied do-loop again end do end program implied

15

EXTERNAL INPUT/OUTPUT FILES

38

If you didn’t quite follow that, all it does is get our row value (integer i) and then reads in the array values for each column (using integer j - that’s the implied do-loop bit) at constant i. Once finished with all the columns, it goes back to the next row and first column. Everything then repeats. So that’s us entered our values in by row order, as opposed to the standard column order. We then print it out as we would expect to see a normal matrix, row number increasing as you go down, column number increasing as you go right.

14.8

Allocatable Arrays

Sometimes there are situations when you do not know how large your array is going to be until you are in the middle of your program. For example you might need the user to define how many planets are in your simulated solar system. So how then do you declare your array variable if you don’t know it’s dimensions from the start?! Well, there is a very useful command called allocate which allows you to leave the size of an array undetermined until you need to put values into it. You can tell the computer that you want a specifically named array, with as of yet undefined size, set aside. You do this with the following declaration statements: real, allocatable, dimension(:) :: x This is for a real rank one array (ie. a list of real numbers) real, allocatable, dimension(:,:) :: y This is for a real rank two array (ie. a 2D table of real numbers) We now have two specifically named arrays with nothing but their rank assigned - you must assign the rank, so you do need to know whether you want a list or a table before you start. So let’s say we now want to ask the user how many objects there are in our solar system and also how many time-steps they might want. We simply need to read in some integer values and then use the allocate command to assign the sizes of the array: print *, ’enter integer values for the size of your arrays:’ read *, a,b allocate (x(a) , y(a,b)) So in this example you have allocated the real number array x to be a list of numbers of length a. You have also declared y to be table consisting of a rows and b columns. You can of course use any technique to obtain a and b, not just by reading them in - but be warned that they have to be integers! You can’t have six and a half numbers in your array. When you are finished working with an allocatable array, you will want to deallocate an array. This should be done, if you are repeating operation of a program (say the user wants to rerun your program from the start from the beginning without exiting execution of the program). It is also good practice to deallocate an array when you are done with it since it will free up computer memory. This is done like so: deallocate(x,y)

15 15.1

External Input/Output Files Reading in .DAT Files

In a lot of real situations, data often comes in the form of files which contain multiple columns of numbers, sometimes reaching huge sizes. These usually contain data from observations such as, for example, date of observation, I-band magnitude, error in I-band magnitude (what my summer project

15

EXTERNAL INPUT/OUTPUT FILES

39

revolved around). We need to learn how to get Fortran to read in these data values, which is an essential skill. For this we will need the commands open , read , close. The open command basically tells Fortran to access a file on the computer, so you have to tell it where to find it. You can then use the read command, usually with an implied do-loop, to read in data values from the file. You will then close the file. So before you start you will need to know a few things about the file you will be accessing. Ideally you want it to be a .dat (eg. planet.dat) file containing no words, but just columns of numbers, each with the same number of values in each column. You can open a .dat file with the kate text editor and most likely with the other good ones as well and you should do this to check and see that your file does contain numbers in the above described way. You will also need to know the full path to your file and the file’s name. For example, my numbers1.dat file which contains three columns of 20 numbers each (so 60 numbers in total) might be located in /home/astronomy/as3013/datfiles which would end up in my folder called datfiles. Note that it becomes a real pain if you give folders names with capital letters or with spaces in between words, like My Documents - please try and rename all your folders, so that they look more like mydocuments. Since we are using the terminal to compile our programs, we will probably find ourselves already located in the /home/astronomy/as3013 folder. So let us look more closely at the open command now that we know where our file is, and what size of table of numbers it has. Let us start with an example: open(unit=7 , file=’/home/astronomy/as3013/datfiles/numbers1.dat’ , status=’old’) Since by the terminal we already are in /home/astronomy/as3013, we could also use: open(unit=7 , file=’/datfiles/numbers1.dat’ , status=’old’) This opens or accesses the file numbers1.dat. The first bit, unit=7, just designates the file a place to stay while Fortran accesses it. The reason I use unit=7 is because you should not set that number between 1 and 6 since they are set aside for other things. You should set it between 7 and 20. You can open up to probably about 90+ files, by increasing the unit value, but realistically you should be fine with up to 20. The second bit, file = , just tells Fortran where to find the file. The third bit, status = ’old’ should be included if you are opening an existing file and in this case we are, so we use old. If we wanted to create the file that we are opening here use ’new’ instead. So we now have numbers1.dat stored in unit 7. We can now read the data in from the file. Let’s say that I wanted to make my three columns into different arrays, time , mag and error, all of length 20. The bit of code I am about to supply to you may not be the most efficient way doing this, so please tell me if there is a better way of doing it: program readingstuff implicit none integer, parameter :: rows=20,cols=3 real, dimension(rows,cols) :: datfile real, dimension(rows) :: time , mag, error integer :: ioerr open (unit=7 , file=’/datfiles/numbers1.dat’ , status=’old’) do i=1,rows read(7,*,iostat=ioerr) (datfile(i,j) , j=1,cols)

16

FUNCTIONS AND SUBROUTINES

40

end do if (ioerr .eq. 0) then print *, ’data read successful’ else print *, ’data read unsuccessful’ end if close (unit=7) do i=1,rows time(i) = datfile(i,1) ! time values from the first column of our .dat file mag(i) = datfile(i,2) ! mag values from the second column error(i) = datfile(i,3) ! error values from third column end do I think most of that should be easy enough to follow, except for the unusual looking use of the read command. The first part just specifies that we are reading from the file that currently resides in space 7 (which is where our file is residing). The next bit you should just leave as * (it is to do with list directed input I think). The third part is there as a safety feature, we assign an integer to variable ioerr which is returned as 0 if our data read was successful and 1 if our data read was unsuccessful. We then close space 7 which gets Fortran to free up that space by kicking out the file that was there. We then make our three seperate arrays from the data file - mission accomplished!!

15.2

Creating .DAT Files

Creating your own .dat files is very easy. Just open a text editor and enter a single column of numbers. We could then add a new column of numbers, all we need to do is leave at least one space in between the number of the previous column and the number in the new column: 12.4 34.6 123 13.5 45.2 145 19.4 12.5 456 11.0 23.3 120 2.44 5.3 567 3.6 5.333 234 You would then save this as, for example, test.dat wherever you like you using the text editor and there you go, you’ve created a .dat file!

15.3

Writing Data to External Files

TBD

15.4

Using Text Files to Fill In Read Commands

TBD

16

Functions and Subroutines

We now move on to a very important topic, one that you will certainly be making much use of when you start making more complex codes. What are functions and subroutines? What they are is independant blocks of code that act like a new program, but which can be called up by other functions or subroutines to perform certain tasks.

16

FUNCTIONS AND SUBROUTINES

41

So you will have one main program in your code, but this may make use of any number of functions and subroutines, and these functions and subroutines can themselves make use of any number of other functions or subroutines. In other words, you can break down your problem into many smaller pieces. It also allows you to make ’black-boxes’ (ie. blocks of code that perform a certain procedure that you know work, which you can then use over and over again). There are two uses of these functions/subroutines, either internal or external, but we will consider only external functions/subroutines since they are more useful, if potentially a bit harder to learn to start off with. You may look up information on ’internal’ procedures on one of the given website fortran tutorials. So typically, if say you need to make repeated use of a certain equation, like say working out the mean value of a set of numbers, you can write a subroutine or function that will calculate the mean value of the inputted values and return it as output. You can then call up this program unit whenever you want to get the mean, instead of repeatedly writing out the same bit of code to work out the mean each time. Every function/subroutine will typically have both input and output variables. So you can choose what values you are inputting to your function/subroutine, and this will give you your relevant output. For example, we might input an array of numbers and get back a single value for the mean. Please also note that functions and subroutines are not the same, and are coded differently - in some situations it is better to use functions, in some it is better to use subroutines. You will get a feel for what is better in what situation with experience and a little bit of guidance.

16.1

Functions

Let us look at the first line of our function by example: You will need to declare the type of variable your function output is, so will it be an integer, real, double precision, etc . . . You will then give your function a name, and the name that you use is quite important since it will be the name of your output. You will then finally list the input variables that you will be using in your function. So your first line might be something like: real function stars(a,b) In this case, our output is called stars, which is declared to be a real number. Our input variables are a and b which as of yet have no declared variable type. They will not be assigned initial values inside the function typically, since they will be given values by the variables you are using as input from your main program. Hence a and b are given the name dummy variables since they are effectively representing the input from the calling program (the program that is making use of them). Next we need to declare our variables (remember to still use the implicit none command before declaring the variables) - we will need to declare our input (dummy) variables and any other variables which the function will use, except the output which is already declared. Our function will now look like this: real function stars(a,b) implicit none real :: a , b integer :: c real :: time We will then need our execution statements, which at some point must assign a value to our output, followed by the end function command to signify the end of the coding block. Let’s look at the simple example of a function which takes in two real numbers, performs some calculation and then returns the output:

16

FUNCTIONS AND SUBROUTINES

42

real function stars(a,b) implicit none real :: a,b integer :: c real, parameter :: pi = 3.141 print *, ’please enter an integer value for c index:’ read *, c stars = (a*b)/pi + real(c) end function gold This is a pretty simple example, but functions are pretty much independant little blocks of code, so you could make them as complicated as you want. Try to make it so that each function has one main purpose (ie. one output value). Please also try to get into the habit of adding comments at the start of your functions, saying what it’s purpose is, what the input variables mean and what types they are, what the output represents, what bugs it has, etc . . . ! ! ! !

Function by Colin Simpson Last Modified: 7/7/07 Purpose: Calculates the number of stars, given a user input value for the c-index Bugs: Pi not accurate enough

! Inputs: ! 1) a : real : the a-index value ! 2) b : real : the b-index value ! Output: ! 1) stars : real : the number of stars So you know how to make a function, but how can you actually use it? Let’s continue with the above example, but let us instead look at how to use the function in our calling program (the program that makes use of the function on that particular occassion). If in your main program you want to use a function, you will need to declare the function output, so in our above example, we would need to declare the real variable stars in our main program if it makes use of that function. We do not need to declare a, b, c or pi explicitly since they are declared by the function and will not feature in your main program. You will however need to declare the input variables you will be using (ie. the ones that assign the initial values to a and b). So if we had two values alpha and beta in our main program, we could use them in stars to work out the value of stars. To make things clearer, let us look at the actual code we would use: program test1 implicit none real :: alpha, beta real :: stars , stars1 , stars2 print *, ’enter values for alpha and then beta:’ read *, alpha, beta stars1 = stars(alpha,beta) alpha = alpha*0.8 beta = beta + 24000.0 stars2 = stars(alpha,beta) print *, ’the initial number of stars is:’ , stars1 print *, ’the final number of stars is:’ , stars2

16

FUNCTIONS AND SUBROUTINES

43

end program test1 So notice here how we put alpha and beta inside the brackets defining the function input - these then assign the numerical values to a and b in our function. We also change the values for alpha and beta and this can then be used as new input to give us two separate values for number of stars (ie. we get stars1 and stars2 ). So try using this code; you will need both the main program and the function to be present in the same file, but with each block of code to be seperated a few blank lines. This is why they are called external functions. You may have noticed that in this example, there isn’t really that much point to using the function, since you could just as easily write it into the main program, but they are useful when the functions are used repeatedly and also for keeping things organised. This is a very short introduction to functions, so please have a go at writing some since that will be the best way to learn how to use them effectively.

16.2

Subroutines

A subroutine is somewhat like a function in that it has both output and input, except that it has more flexibility, in that you can have a variable being both input and output, multiple outputs, more flexibility with the output types etc... so unless you’re wanting to just work out one output value, you may find you make more use of subroutines. Your first line will include subroutine followed by the name of the subroutine, which, unlike functions, does not represent any variables. It is just a name which you will use to call up your subroutine, as you will see later. Following the name of the subroutine will be all of the input and output variables enclosed in brackets, called the arguments: subroutine starscalc(a,b,stars) This subroutine has three input/output variables, which are a , b and stars. Note that your subroutine name should not be the same as that of any of the variables, or you will get an error. We next need to declare all of the variables inside the brackets, as well as any of the other variables the subroutine will use. We will then have our execution statements, whatever they may be, followed finally by end subroutine to close this block of code. So if we want our subroutine to perform the same calculations as that of our function stars, we would need this subroutine: subroutine starscalc(a,b,stars) implicit none real :: a,b,stars integer :: c real, parameter :: pi = 3.141 print *, ’enter an integer value for c index:’ read *, c stars = (a*b)/pi + real(c) end subroutine So how do we make use of our new subroutine? Very much like how we used our function, but with a slight difference in the coding required. We shall have to use the call command in the program that is making use of the subroutine: program test2 implicit none real :: alpha, beta

16

FUNCTIONS AND SUBROUTINES

44

real :: stars1 , stars2 print *, ’enter values for alpha and beta:’ read *, alpha, beta call starscalc(alpha,beta,stars1) alpha = alpha*0.8 beta = beta + 24000.0 call starscalc(alpha,beta,stars2) print *, ’the initial number of stars is:’ , stars1 print *, ’the final number of stars is:’, stars2 end program test2 Again, try testing out this piece of code. Include both blocks of code in one file, with each block seperated by some blank lines. Like with functions, it is also a good idea to add comments to your subroutines, saying what the purpose of the subroutine is, what the input/ouput variables mean etc . . . We can see that both the function and subroutine presented above do exactly the same thing and are coded mostly in the same way. That is because we are dealing with a simple one output calculation. However, we should note some key points about subroutines and then go on to look at a more complex example which cannot be done so easily with a function. With subroutines, it is possible for any of the variables in the brackets in the first line to be both input and output. If in our above example say, we were to change a in some way inside the subroutine, then alpha would actually be changed to equal the new value of a when we call up our subroutine, which we have in some way changed from the original inputted alpha (mulitplied it by 2.0 for example). This can at times be a problem if you re-use that altered variable again as input, without realising that it’s value has in fact been changed. This is important so here is an example: program test3 implicit none real :: alpha,beta real :: stars print *, ’enter values for alpha and beta:’ read *, alpha,beta call starscalc(alpha,beta,stars) print *, ’the number of stars is:’ , stars print *, ’alpha was changed in the subroutine!’ print *, ’the new alpha is:’ , alpha end program test3

subroutine starscalc(a,b,stars) implicit none real :: a , b , stars real, parameter :: pi=3.141 integer :: c print *, ’enter an integer value for c index:’ read *, c stars = (a*b)/pi + real(c) a = a*2 ! we have altered ’a’ which will affect ’alpha’ in the main program end subroutine

16

FUNCTIONS AND SUBROUTINES

16.2.1

45

More Complex Subroutines

TBD 16.2.2

Arrays in Subroutines

TBD If you hadn’t already guessed, you can use arrays as input and output. I will not go into detail, but quite often you will need to include the array sizes as integer input/output variables: subroutine arrayness(array1,size , array2) implicit none integer :: size ! you will need to declare integer array size before the array real, dimension(size) :: array1 , array2 integer :: i do i=1,size array2(i) = 2.0*array1(i) end do end subroutine There can be a complication with array sizes however. If say you were creating a more general subroutine which could cope with an array of max 20 numbers, but on a certain occassion you were inputting an array of dimension only 5, then there can sometimes be a problem with the compiler spreading these 5 inputted values out between these 20 spaces in the computers memory. For such cases, it may be wise to use instead: subroutine arrayness(array1,lsize,psize , array2) implicit none ... real, dimension(psize) :: array1 ... In this example, lsize is the logical size (the amount of numbers) and psize is the physical size which could be the theoretical maximum size of the array. You shouldn’t need to worry too much about this problem, but try to remember that a potential for error exists here, in case you ever get some unusual results when using arrays in subroutines and functions.

16.3

Points of Interest

There are a few more useful points about functions/subroutines which you should know: 16.3.1

Variable Types

You must keep variable types constant, for example if you were to input a real variable alpha into a subroutine as input for double precision variable a, then the two types are not constant and your code will not compile. If you really need to have alpha as real and a as double precision, you can use the dble() operator when calling up your subroutine: call dandelion(dble(alpha),beta , stars)

17

MODULES

16.3.2

46

Same Variable Names

It is perfectly legitimate to have the same variable names in your call command and your subroutine. Sometimes it is much easier to follow the code if you do, sometimes it is not good though, but there is nothing to stop you doing it. You can have either one, all or none of the variable names matching: call same(alpha,delta, gamma) ... subroutine same(alpha,beta, gamma) ... You just have to remember what name you have assigned to a variable in each separate programming block. 16.3.3

Intent Command

This useful command has to do with subroutines and the direction of flow of information. If for example you want some of your variables inputted to your subroutine to be only inputted and not returned as output as well, you can use the following command, when declaring your variable in the subroutine: subroutine test1(a,b,c,d) implicit none integer, intent(in) :: a,b real, intent(in) :: c real :: d ... Now if you alter the value of a, b or c inside the subroutine, you will not be able to compile your program. This is because it realises that the original value of your variable is going to be overwritten by a new one when you call up the subroutine. So the intent command can be used as a check for overwriting values. You could instead have a variable which you dont want to have an input value, but which you want to assign a value to so that is returned as output to the calling program. For this you would use: integer, intent(out) :: c , d Let’s now consider what happens if we want a variable to be both inputted and outputted, so that it is input by the calling program, the variable will then be updated during the subroutine and will be returned as a modified value to the calling program: eg. integer, intent(inout) :: e , f A typical variable in a subroutine already has this inout attribute, but it is nice to have the intent explicitly showing this. The intent command then is most useful to check to see if you are accidentally overwriting variable values and is a good safety mechanism to have in place.

17

Modules

So having looked at both functions and subroutines, let us look at an additional type of independant coding block - the module. This is a new feature to Fortran and potentially a very useful one. You might not need this knowledge for some time, but feel free to read on, since modules can be be very useful when you want to create a library of functions and subroutines that you have made. You may well find yourself wanting to do this if you have made a group of functions that say work out a number of statistical properties of a sample array. A module usually contains one or more of the following things: variable values, subroutines, functions. So your module might contain a list of lot’s of physical constants like Planck’s constant or Pi.

17

MODULES

47

It might contain some useful functions for getting the mean, variance, median etc . . . of a given array. It can contain any number and any mixture of diffferent variables, functions and subroutines.

17.1

Creating Modules

To create a module, you go about it in a very similar way as to how you would go about creating a normal program. It will typically be in it’s own seperate file, so you will not include it in the same file as a program, like we previously have done with subroutines and functions. 1. Your module will start with the command module followed by the name of the module, which you should choose sensibly since this name will be used by programs to link with your module. You will not have any arguments after the name, like we had with functions and subroutines. module celsius2kelvin 2. You will then include any global variables that you wish to choose. These global variables will, have they been given values, be accessible by any of the functions/subroutines in that module. module celsius2kelvin implicit none real, parameter :: abszero = -273.14 ! zero kelvin in celcius Any variables that are declared here can be used by any of your functions/subroutines inside the module without having to redeclare them in your function/subroutine. Note that you can not do any calculations here. All calculations in a module can only be performed within the functions and subroutines that the module contains. Also note that you do not have to have any variables, and if you dont you should also leave out the implicit none command. 3. If you then want to include functions/subroutines, you will need to use the contains command in the way shown in the later example. You should only do this after declaring all the global variables first. 4. You will then need to include your functions/subroutines, each of which should be included seperately and in it’s entireity. module celsius2kelvin implicit none real, parameter :: abszero = -273.14 contains real function kelvin(celsius) ! takes in celsius and returns corresponding kelvin implicit none real, intent(in) :: celsius kelvin = celsius - abszero end function kelvin real function celsius(kelvin) ! takes in kelvin and returns corresponding celsius implicit none real, intent(in) :: kelvin celsius = kelvin + abszero end function celsius 5. Once you have finished creating your module, you simply use the end module command to finish up. This should be done after all your functions and subroutines in the module have been created.

17

MODULES

17.2

48

Linking Programs and Modules

So let’s imagine you have created two modules, one full of physical constants (lets call it physconst) and another with a range of physics functions that do cool physics things (lets call that one physfunc). It is likely that you are going to require physfunc to access the module physconst so as to use those lovely constants. We will need to do this on both the linux command line and in the source code. Let’s first look at how to do it in the source code. 17.2.1

Linking in Source Code

We shall look at the code required in physfunc to access the other module. It should be done before anything else in the module and with the use command: module physfunc use physconst ! this initiates usage of that module ... contains ... put all your physics functions and subroutines in here ... end module You could add any number of modules to be accessed, so lets say we also require modules cool and sad to be used by physfunc: module physfunc use physconst , cool , sad ... Or this can alternatively be written as: module physfunc use physconst ; use cool ; use sad ... That is how to link modules together, but what if you want to access modules from a main program? It is exactly the same procedure: program test use physconst, cool , sad ... progam test use physconst ; use cool ; use sad

17.2.2

Linking in Command Line

Next we look at how we link the files containing the programs and module together, through use of the linux command line since it is not sufficient just to make use of the use command in the source code. The trick in this is to compile all the files needed in the one go, all of them combining together to make the one executable file that will do (hopefully) what we need done. So let us go back to our case of the physfunc, physconst and our program test (we shall forget about cool and sad modules for this example). Our program test might be stored in a file called test.f90, the physfunc module in a file called physfunc.f90 and physconst in a file called physconst.f90.

17

MODULES

49

They should all be placed in the same folder/directory so that when you use the ls command on the linux command line, you can see all three files appear as being in the same directory. We want to compile all three of them to make one executable file, let’s say textbftest1, so to do this we enter into command line: physconst.f90 physfunc.f90 test.f90 -o test1 This should now create an executable called test1 which, when run, will run the program test which will call upon the modules physconst and physfunc. The ordering of the file names in the above example is very important. We can imagine that a spider-web represents a folder, with lines (with directional arrow included) joining the objects (modules and programs on the web). You want to list on the command line the necessary files in order of priority on the ’web’, with the first file being the one that is used and makes no use of any other files, right up to the last one that is not used by any other object but instead makes use of other objects.

17.3

Selective Module Usage

There are often cases where you do not want to access all the components of a module. You might say have a huge collection of functions and parameters in your module, but you might not want to use more than a couple of them. It can in these cases be a good idea to use the following command to help you ease the computers workload. Note that the technique I will now show you does not change the way in which you would compile your program - to make this clear I will go back to the same example of modules physfunc, physconst and program test. If you wanted in your program to access only one function out of physfunc, let’s say this function is called starscalc(alpha,beta,gamma) and only want to use two parameters from physconst, let’s say parsec and arcsec. If we were to only need these then we can use the only command which is implemented in the following examples: module physfunc use physconst , only: parsec , arcsec ... end module

program test use physfunc , only : starscalc ... end module To make this into one executable file like last time we would enter onto the linux command line the following: physconst.f90 physfunc.f90 test.f90 -o test That is pretty much all there is to the use command, it is not essential to use it, but will speed things up when you’ve got a lot of things in your modules.

17.4

Additional Info

Some additional notes on modules might be helpful also: 1. Your functions/subroutines can call up any other function/subroutine contained with that same

18

SOME USEFUL COMMANDS

50

module or any other module used by it. 2. I will leave it to you to discover how exactly to go about declaring the variables when calling up other modules etc... sorry but it would take me too long to explain every detail. Remember to use the intent command in your functions/subroutines to make sure data isn’t being overwritten or whatnot since the normal rules will still apply.

18 18.1

Some Useful Commands Pause Command

The pause command simply halts the program at that point until the user presses return. There will usually appear a message to the user to press return, so that they don’t just sit there wondering how long the program is going to take. You can also include printable text in your command: if (c .gt. b) pause ’you have c greater than b’ pause Typically you will not want to include these in your program unless it is to display some important information that you want the user to see that would otherwise flash past without being seen. If it is likely the user will run off to get a cup of coffee as you have printed an earlier statement saying that some lengthy calculation was under way, it would not be wise to put in a pause command as it halts execution until the user presses return.

18.2

Dot Product Command

A useful thing to be able to do is work out the scalar dot product of two one dimensional arrays. So if we had two arrays, (a1,a2,a3,.....,a19,a20) and (b1,b2,b3,....,b19,b20), and please note that they must be of the same size, we can work out: a1*b1 + a2*b2 + ..... + a19*b19 + a20*b20 - (this is the dot product) So let’s look at an example where we store the dot product into variable indigo, which should be real if the arrays are real, integer if the arrays are integer, etc... : indigo = dot product(a,b)

18.3

Matmul Command

Matmul is a mathematical command that takes two matrices and performs matrix multiplication. The two matrices you multiply will have to fulfill the common requirement of all matrices that undergo matrix multiplication, which is that the number of columns in the first matrix must equal the number of rows in the second matrix (otherwise the compiler will complain): program test implicit none integer, parameter :: m=4 ,n=3 , p=2 real, dimension(m,n) :: a real, dimension(n,p) :: b real, dimension(m,p) :: c integer :: i,j do i=1,m do j=1,n a(i,j) = 2.0 * real(i) end do end do do i=1,n do j=1,p b(i,j) = 3.0 * real(j)

19

PLOTTING PACKAGES

51

end do end do c = matmul(a,b) print *, ’my multiplied matrix is:’ do i=1,m print *, (c(i,j) , j=1,p) end do end program test

18.4

Random Numbers

If you want random numbers to be generated by the computer, then you closest you can get is to get a set of pseudo-random numbers (they are random based on an integer code value). This set of random numbers turns out to be the same each time, though there are some fairly simple codes available which allow you to create truly random numbers. Here are two ways in which to use the inbuilt random number subroutine to make these pseudo-random numbers, where the numbers will be between 0 and 1: program random as can be implicit none real :: chips ! we only want one random number in this example real, dimension(100) :: fish ! will give an array of 100 random numbers integer :: i call random number(chips) call random number(fish) print *, ’no. of chips’, 10*chips ! the above line prints a number bewteen 1 and 10 print *, ’weight of fish 23:’, fish(23) end program

18.5

More Mathematical Functions

Here is a list of some more mathematical commands provided by fortran: 1. dsqrt(a) This will return the square root of double precision number a 2. csqrt(a) This will return the square root of a complex number a 3. max(a,b,c,. . . ) This will return the largest value in the list of variables a,b,c,. . . 4. min(a,b,c,. . . ) This will return the lowest value in the list of variables a.b.c.. . .

19

Plotting Packages

You will need to be able to make graphs of data, usually with lines, data points, numbered and labelled axis, etc... There are a number of different graphical plotting packages, three of which are commonly used in astronomy: PGPLOT, GNUPLOT, Supermongo.

19

PLOTTING PACKAGES

19.1

52

PGPLOT

PGPLOT is basically a library of subroutine packages that you can manipulate to create graphs, usually through the use of arrays of data values. There are a huge number of available subroutines, but making a simple graph requires just a few of them. PGPLOT suffers from a problem in compatibility between machines - the plotting subroutines are embedded in the source code (unlike with the other two), meaning that the source code will not compile on computers which do not have PGPLOT installed. 19.1.1

Basic Operation

The basic six subroutines that we shall make our graph with are: 1. PGBEG This initialises the beginning of making a plot 2. PGENV This sets the size and style of the box we will be drawing in 3. PGPOINT This will be used to plot data points (which can be set to look pretty!!) 4. PGLINE This will be used to draw our pretty lines 5. PGLAB This will be used to label the axes and our graph 6. PGEND This will cease the process of plotting So let us consider the scenario where we have collected a bunch of data points which we are expecting to be very similar to a well defined function. Let’s look at how to plot both the points and the curved line denoted by the funtion. 19.1.2

PGBEG

We shall first have to start the plotting with PGBEG: PGBEG(unit, file, nx, ny) unit : this is an integer that is only present for historical reasons and should be set to 0. file : this is usually enclosed in ’ ’ and defines the name of the output graph and what device should be used to plot it (look at the example later, might make this more clear). nx : an integer stating how many subsections in the x-direction the page for plotting on will be split up into. ny : in integer stating how many subsections in the y-direction the page for plotting on will be split up into. These are some examples of how you might use PGBEG, but let’s look at each one in detail: call PGBEG(0, ’?’, 1, 1) This example has no specified output name or device to be used. If you use just ’ ? ’ then during run-time the user will be asked to supply a device to be used. If the user enters another ’ ?’ then you will get a list of possible devices. In there should be a PS device called postscript, this is typically the device I would use. How do we use it though? Well, an alternative to the above example might be:

19

PLOTTING PACKAGES

53

call PGBEG(0, ’plot.ps/ps’, 1, 1) In this example we will be creating one graph on one page that will be saved as a postscript file in the folder containing your executable program, under the name plot.ps. It will overwrite any other postscript files with that same name, so be sure to check the folder for any other graphs of the same name - it will be automatically overwritten. I’ve lost a few graphs in this way which were a pain to try and remake, so be careful of that. Let us look at a couple more examples: call PGBEG(0, ’plot.ps/ps’, 2, 1) call PGBEG(0, ’plot.ps/ps’, 3, 3) In the first example we would be splitting the page down the middle and plotting up to two graphs on the one page and in the second example we would have up to up to nine graphs on the one page. The best way to get used to these is with experience. 19.1.3

PGENV

We typically use the PGENV command when we want to set the axis limits for a simple graph. It will typically be used after PGBEG. If say you tried to plot the data points before using this command then your data points will not know where to go so you may end up with an empty graph. PGENV(xmin, xmax, ymin, ymax, equal, axis) xmin : this is a real number defining the lower x-axis limit xmax : this is a real number defining the upper x-axis limit ymin : this is a real number defining the lower y-axis limit ymax : this is a real number defining the upper y-axis limit equal : this is an integer with value set to either 1 or 0 if equal is equal to 1, the axes will be scaled equally (per inch), otherwise they wont be axis : this can be a whole host of different integers, each of which does something different: axis = -2 : draw no box, axes or labels axis = -1 : draw a box only axis = 0 : draw box and label it with coordinates (standard) axis = 1 : same as axis=0 but also draw the coordinate axes (line at x=0 and y=0) axis = 2 : same as axis=1 but also draw grid at major incrememnts axis = 10 : draw box and label x-axis logarithmically axis = 20 : draw box and label y-axis logarithmically axis = 30 : draw box and label both axes logarithmically Hopefully that should be self-explanatory, but here is a simple example: call PGENV(-10.0, 10.0, 10.0, -10.0, 0, 0) Note here that I have made +10.0 my lower y-axis limit and -10.0 my upper y-axis limit, so the scale is now pointing in the reverse to what we normally expect. 19.1.4

PGPOINT

Ok, so now we have used PGBEG and PGENV to intialise our graph plotting and to make a ’window’ into which we can plot things. So what are we going to plot? Well, let’s say that we have our data points from some experiment stored in two arrays of size n. We can use the PGPOINT command to plot these points, given that they lie within the ’window’ defined by PGENV from earlier. Here is how PGPOINT works: PGPOINT(n, xpts, ypts, symbol)

19

PLOTTING PACKAGES

54

n : an integer defining how many data points you are wanting to plot xpts : a real array containing the x-axis values of your points (eg. time) ypts : a real array containing the y-axis values of your points (eg. velocity) symbol : an integer which denotes the type of symbol to be used (try different values to find out what number gives what symbol) So let us look at an example where we have an array time of size n containing time values and an array velocity of size n containing our velocity values at each time, time(i) from i=1,n. call PGPOINT(n, time, velocity, 6) Pretty simple right? Well, for the most part, but there is one slight problem that you have to watch out for. The inputted arrays must be of real type. If not then use real() on the array to make it real. So let’s say you wanted to plot your integer array time with each time point having the value 5.0 taken away from it (you might want to start your x-axis at x=5 let’s say): call PGPOINT(n, real(time)-5.0, velocity, 6) We can use this called subroutine as many times as we want, so if you have two data sets that you want to compare, you can plot both of them on the same graph, just use the PGPOINT again. You might want to change the symbol integer for your new data set, otherwise you wont be able to distinguish between the two data sets. 19.1.5

PGLINE

You may also want a line for your graph. Usually a line represents values of a well defined function or mathematical model. The line is generated from a number of smaller lines that ’join the dots’ between the function data points. So to get a nice smooth looking line, you will need to have the x-axis data points to be in ascending or descending order in their array. If you don’t, your line is going to jump back and forth between hugely different x-axis values. To get a really smooth line, you will also want quite a lot of data points. If you are plotting the line of a mathematical function? You will want to create an array of your function generated points. So if you have your time data points and you have velocity as a function of time, then generate some relevant array of time values, feed them into your function which will then generate your velocity points. You might want these arrays to be about 500-1000 values so as to get a smooth line. You may have to try playing about with this till you get the hang of it. Here also is a nifty little bit of code for if you are trying to create your array of time new values that lie in the range of your original time data points (time array of size size has to be in either ascending or descending order remember - this code is for ascending order): do i=1,n ! n should be about 1000 typically time new(i) = (time(size)-time(1)) ! this is the range of the original ’time’ points time new(i) = (time new(i)/real(n)) ! this divides the range into ’n’ equal divisions time new(i) = (time new(i)+time(1)) ! this creates your n ’time new’ points within the original range end do You could now run these n values through your mathematical function to give you n values for velocity new. You would then be ready to plot your line. Now let us look at how to implement PGLINE : PGLINE(n, xpts, ypts) n : integer defining the size of the arrays to want to draw a line to xpts : an array of size n containing your x-axis data points ypts : an array of size n containing your y-axis data points

19

PLOTTING PACKAGES

55

Like with PGPOINT, you can call this is as many times as you like for each graph. The arrays must also be real otherwise use the real() conversion. So for example: call PGLINE(n, time new, velocity new) call PGLINE(t, real(frequency)-1.0e6, real(wavelength)) ! a slightly random example perhaps... 19.1.6

PGLAB

This is an easy to use subroutine that labels the axis. I will not go through how to use special characters or symbols in your labels here, but I will later reference a good place to find out how it is done. So, you can use PGLAB at any point you wish, as long as PGBEG and PGENV have been used: PGLAB(xlbl, ylbl, toplbl) xlbl : this is text, either a character variable or text placed directly in, that labels x-axis ylbl : this is text, either a character variable or text placed directly in, that labels y-axis toplbl : like the above, but acts as a title for the graph So this is pretty self-explanatory, but here is an example or two in case its not clear: call PGLAB(’time (s)’ , ’velocity (m/s)’ , ’graph of velocity vs time’) call PGLAB(str1 , str2 , title) ! where these are all character variables 19.1.7

PGEND

If you want to finish plotting using PGPLOT, you simply use: PGEND That’s it! Once you do this, any more PGPLOT commands you use will be invalid and wont do anything. This is until you enter PGBEGIN(. . . ) again, then a new plot will be started. 19.1.8

A Useful Source

So we have looked at the simple case of drawing graphs. Commands such as PGENV and PGLAB though are merely less general (and hence less powerful) versions of other commands. There are the subroutines like PGSVP, PGSWIN, PGMTXT, etc. . . which do more general purpose actions. I think though that for the moment you should be content with the above, but if you want to find out about how to have more control over the way your graph looks, then you should go the following website: http://dsnra.jpl.nasa.gov/pgplot/pgplot.html

19.2

GNUPLOT

GNUPLOT is the second graphical plotting package we shall be going through the workings of. It is easier to use than PGPLOT and highly intuitive. To use this program you will again need your required data to be stored in a separate file such as a .txt or .dat file. 19.2.1

Getting started

To start up gnuplot, go to the folder your datafile is in using the terminal, and type into the terminal: gnuplot Then, to plot the data, simply type: plot ’data.txt’

19

PLOTTING PACKAGES

19.2.2

56

Specifying columns to plot

If you have a file with more than two columns, you can specify which ones to plot. So say you want to plot column 1 on the x axis and column 5 on the y axis, type: plot ’data.txt’ using 1:5 You can combine several columns in mathematical operations, by appendix dollar signs to the column numbers, and specifying the operation in brackets. For example to plot column 1 minus column 2 on the x axis and column 3 times column 4 plus column 5 on the y axis, type: plot ’data.txt’ using ($1-$2):($3*$4+$5) 19.2.3

Specifying window ranges

You can also specify a range of x and y values for the window: plot [0:10][0:20] ’data.txt’ using 1:5 This will plot from 0 to 10 on the x-axis and from 0 to 20 on the y-axis. 19.2.4

Specifying labels

You can include labels on the x and y axis before plotting: set xlabel "Time (yr)" set ylabel "Number" plot ’data.txt’ 19.2.5

Log-Log plots

To produce a log-log plot and then a non-log plot of the same thing: set logscale plot ’data.txt’ unset logscale plot ’data.txt’ If you wish to make further log-log plots you can simply use set logscale and all plots subsequent to that will be log-log plots until unset logscale is used. 19.2.6

Lines and dots

Instead of crosses, you can plot with a line or with dots: plot ’data.txt’ with lines plot ’data.txt’ with dots 19.2.7

Saving your plot

Now you might want to save your plot to a file so as to be able to print it or incorporate it into a file later. Most of the time you will want to create a postscript file. If required these can be converted to pdf as is shown later. The default device that gnuplot writes plots to is the display (also called x11). In order to create a hardcopy of a plot, you need to change the device from x11 to postscript, then specify a filename: set term postscript set output ’myfirstplot.ps’

19

PLOTTING PACKAGES

57

Then, enter all the plot commands as you would have done to display the plot on the screen. Once you have finished, switch back to x11 to close the plot: set term x11 In order to produce a color postscript file, type: set term postscript color set output ’myfirstplot.ps’ So let’s say you want to produce a file showing data.txt with labels on the x and y axis, here’s what you would need to do: set term postscript set output ’myfirstplot.ps’ set xlabel "Time (yr)" set ylabel "Number" plot ’data.txt’ set term x11 Note that when you are writing to a postscript file, the plot on the display will not change, because you are sending instructions to the postscript file rather than the screen. NOTE : gnuplot plots the points, lines, box, and labels all at once with the plot command, so if all the labels are set the way you want them, you only need to open the postscript device, plot the data, and change the device back to x11. If you want to view the plot, you will need to exit gnuplot and then type: exit gv myfirstplot.ps To print the plot, you can type: lp -Psenlab myfirstplot.ps Or if you are on a linux machine, you can also use kview myfirstplot.ps from which you can print directly. That’s it! gnuplot is much more powerful than this however, so make sure you check out the documentation: http://www.fnal.gov/docs/products/gnuplot/manual/

19.3

SUPERMONGO

The final plotting package we shall look at it is supermongo, an alternative to gnuplot. 19.3.1

Getting started

First, you will have to copy over a .sm file to your home directory. To do this, open a terminal and type: cp /home/star/tr9/.sm . This is the configuration file for supermongo. You should never need to edit this (unless you want to change for example the name supermongo greets you by for example!). To start up supermongo, type:

19

PLOTTING PACKAGES

58

sm If all goes well, supermongo will greet you, and a white square window will appear. To plot the data.txt file, you first have to specify which datafile you want to use: data data.txt Then, you need to read whichever columns you need into variables: read x 1 read y 2 This will store column 1 in a variable called x and column 2 in a variable called y. Now, you need to specify the limits of the window. You can either let supermongo decide what is best: limits x y or you can specify the limits yourself: limits 0 10 0 10 You can now plot the coordinate axis: box And finally the data: points x y If you would rather draw a line, use: connect x y To erase the display, type: erase You can include labels on the x and y axis: xlabel Time (yr) ylabel Number To write the plot to a postscript file, you will need to change the device as for gnuplot: device postencap myfirstplot.ps And after you have issued all the plotting commands, you will need to type: device x11 In order to close the plot and return to the screen display. See the gnuplot section for viewing and printing plots. NOTE : unlike gnuplot, supermongo prints labels and boxes whenever you tell it to, so once you have opened the postscript file, you will have to issue the xlabel, ylabel, box, and points/connect commands, before changing the device back to x11.

19.4

EXAMPLES

Here are examples on creating similar plots in pgplot, gnuplot and sm. The text on the right are just comments, so do not type them!

19

PLOTTING PACKAGES

19.4.1

59

PGPLOT

The following code will be embedded in your source code and will access arrays and variables in your code: call call call call call call

pgbeg(0, ’example.ps/ps’, 1, 1) pgenv(-10.0, 10.0, 10.0, -10.0, 0, 0) pgpoint(npoints, x, y, 5) pgline(npoints, x, y) pglab("Time (yr)", "Number", "Example Plot") pgend

This will create the graph which can then be viewed using the terminal commands: gv example.ps lp -Psenlab example.ps 19.4.2

# view the plot in ghostview # send the plot to the senlab printer

GNUPLOT

gnuplot

# start up gnuplot

set xlabel "Time (yr)" set ylabel "Number" plot ’data.txt’ using 1:2 set device postscript set output ’example.ps’ plot ’data.txt’ using 1:2 set device x11 quit

# # # # # # # # #

gv example.ps lp -Psenlab example.ps

# view the plot in ghostview # send the plot to the senlab printer

19.4.3

set the x-axis label set the y-axis label plot the data on the display now tell gnuplot to write to a postscript file and specify the filename plot the data again (you do not need to set the x and y labels again) switch back to x11 (makes sure the plot is closed) quit gnuplot

SUPERMONGO

sm

# start up supermongo

data data.txt read x 1 read y 2 limits x y box xlabel Time (yr) ylabel Number points x y device postencap example.ps box xlabel Time (yr) ylabel Number points x y device x11 quit

# # # # # # # # # # # # # # #

gv example.ps lp -Psenlab example.ps

# view the plot in ghostview # send the plot to the senlab printer

specify data file to use read column 1 into x read column 2 into y work out the x and y limits for the box plot the box plot the x-axis label plot the y-axis label plot the data now tell sm to write to a postscript file plot the box plot the x-axis label plot the y-axis label plot the data switch back to x11 (makes sure the plot is closed) quit sm

20

YOUR OWN PERSONAL COMPILER

19.5

60

Converting Postscript Files

If you run Windows XP, Vista and hence have no way of viewing your postscript graphs on your home computer, you can use the linux terminal to convert the postscript files to PDF files. Using the terminal, make your way into the folder containing the postscript file you want to convert. Now use the following terminal command: ps2pdf plot.ps You can replace plot by whatever your graph is called. You should now have a new pdf file as well as the original ps file.

20

Your Own Personal Compiler

It can be difficult to complete all the exercise sheets during lab hours, especially if you get stuck and find yourself a couple of hours behind. So if you want to be able to program Fortran from your home computer, you will need to get yourself your own personal compiler. The option of which software to use depends on your operating system: • Windows XP and Vista : Salford • Mac OS X : g95 • Linux : g95

20.1

g95

TBD

20.2

Salford

Here I will go through how to install and use the freely available Salford Fortran compiler. This is suited for Windows XP and Vista and can be downloaded from the following url: http://www.download.com/Silverfrost-FTN95/3000-2069-10491439.html?part=dl-Silverfro&subj=uo&tag=button You can get more information on this compiler at: http://www.silverfrost.com/32/ftn95/ftn95 personal edition.asp You should be able to download a single executable application to your desktop, which you can double click to run. It will then ask you to follow it through the set-up procedure. You should with any luck have a successful installation. Right, so down to using this compiler. You should start by opening up the application called PLATO IDE or something equivalent. This is a work station which includes a pretty rubbish text editor (but one that will do you for now), and a whole bunch of buttons which allow you to create executable files. So, you will start by writing your fortran source code into the text editor. You should then save your code with the save button on the toolbar at the top. You can then, once you have written your program, press the compile button on the toolbar (should be on the bottom left somewhere) - you will then see a bunch of comments appear in the seperate box at the bottom of the text editor. It will contain a list of possible errors in your program, red means fatal errors, purple means suggestions you can choose to pay attention to or to ignore. You will also get at the end a line saying if the code was successfully compiled or not - if not you will have to debug the program and try compiling again. If successful, you can then build the program which will create an executable file. This is done using the button to the right of the compile button.

21

CLOSING WORDS

61

If again successful, you can run your program using the run button, which looks a play button on a music player. A terminal-like box should appear and you simply need to wait patiently until the initial writing dissapears and your program begins. Once your program hits a run-time error or finishes execution, you should see a message telling you to hit return - do so and the box will close. You can’t compile and run more programs until you close the terminal-like box.

20.3

Memory Sticks

If you are using your home computer to work on this course, you will need to pass files between the university computers and your own computer. The easiest way (probably) to do this is with a memory stick, something which almost everyone has these days. If you do decide to use a memory stick, instead of for example using FTP or e-mailing yourself files, here is some advice. Plugging your device into one of the computer USB’s will enable the device, but unlike in Windows you will not be asked to open the folder to view it. Instead, go to Start > Home. Now, you should see on the left something called Devices with a plus sign next to it. Click on the plus sign and a list of the memory devices should be present. Have a look around and you should find your memory stick near the bottom of the list. Like in Windows you can now drag files from one folder to the memory stick. Caution: Make sure to copy the files across and not move them across. Moving the files will remove them from the computer entirely, which is how some of my friends lost entire programs, so be careful of this!

21

Closing Words

This information should help you get going with the AS3013 exercise sheets and will hopefully be a useful guide to you in future years. There are of course multiple online Fortran tutorials, but when I was learning, I found many of them to be pitched at quite a high level of experience or knowledge about programming, but you should make full use of them as well. I spent quite a bit of time making these notes, and I would love to hear any comments anyone may have as to how I could improve them, any mistakes there may be etc . . . Good luck with the course.

Smile Life

When life gives you a hundred reasons to cry, show life that you have a thousand reasons to smile

Get in touch

© Copyright 2015 - 2024 PDFFOX.COM - All rights reserved.