Introduction to Programming with Fortran ---------------------------------------- Practical Exercise 08 --------------------- Question 1 ---------- 1.1 Write a module that defines the following: an INTEGER constant maxlength with value 100 a CHARACTER constant message with the value "Kilroy was here" an INTEGER variable errors initialised to zero an ALLOCATABLE REAL array totals Remember to use SAVE appropriately. Compile that to create a module file. 1.2 Write a main program that uses the module, reads in an integer, checks that it is positive and no greater than maxlength, allocates totals to be of that length, and print out the exception status and the message. Check that the program compiles and runs (it doesn't do anything useful). 1.3 Add a subroutine to the module that takes no arguments and prints out the size of the array totals, and call it at the end of your main program. Run it and check that it prints the right answer. Question 2 ---------- 2.1 Write a module that defines the following: three REAL variables, called fred, joe and bill, initialised to zero and contains: a subroutine A with no arguments that adds 1.23 to fred a subroutine B with no arguments B that sets joe to fred+0.7 a subroutine C with no arguments that sets bill to fred+joe a subroutine D with no arguments that prints the value of bill 2.2 Write a main program that uses that module and calls A, B, A, B, A, A, C and D in that order. Compile and test it. 2.3 Change the module to declare the variables PRIVATE, recompile it, and recompile and test the main program. 2.4 Remove the PRIVATE, take out the code for A, B, C and D and create four other modules, each containing one subroutine. When they import data (i.e. the rest of the original module), they should import only the variables that they need. Recompile all modules. You can use either one file for each module or keep all of them in the same file. 2.5 Change the main program to import only the modules containing A, B, C and D and not the one containing the variables. Compile and test it. Note that this shows another way of sharing data between procedures, but not exporting it to users of those procedures. Question 3 ---------- 3.1 Take a copy of the program you wrote in exercise 6, question 3.1, and create a module containing just the function. Compile it but do not link it. 3.2 Convert the main program to use that module, and compile and run it. Question 4 ---------- 4.1 Compile but do not link the file Programs/double.f90 to create a module. Take the file Programs/CubeRoot.f90, and create a separate module out of the functions value and derivative (only). Compile them but do not link them. 4.2 Take the file Programs/CubeRoot.f90, add a USE statement for that module into the main program, and remove the functions value and derivative (only). Compile and link it, and test that it works. It would also work if the USE statement were in function Newton. 4.3 Change the main program in the program in 4.2 to pass value and derivative as arguments (as well as source) when it calls function Newton. Change function Newton to add arguments val and deriv and call them instead of value and derivative. You will need to create interface blocks for val and deriv from the functions value and derivative in the module, and add those interface blocks to subroutine Newton. Compile and like as above, and test that it works. Question 5 ---------- This question is easy to code, but tricky to understand. It shows what is going on with name inheritance. It is very important to understand the why and not just observe what happens. Do not expect the output to have the same values as in the specimen answers, as Fortran random numbers do not work like that. 5.1 Compile the file Programs/double.f90 to create a module. Take Programs/Cholesky.f90, and put the subroutine CHOLESKY into a module Lapack in a separate file. Compile that to create a module file and save a copy of the source. 5.2 Create a main program that contains just the main program from Programs/Cholesky.f90 and uses module Lapack. Compile and link that and check that it works. 5.3 Remove the USE double from the main program, and recompile it. What goes wrong and why? Save a copy of the source. 5.4 Move the USE double in module Lapack from subroutine CHOLESKY to immediately after the MODULE statement, recompile it and then recompile and test it using the main program created in 5.3 above. Why does it work again? Save a copy of the source. 5.5 Now put the USE double back into the main program (i.e. undo what you did in 4.3), recompile it and test it. Check that it still works. 5.6 Now replace the USE double in module Lapack by its source form INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(12) Recompile it and then recompile and test it using the main program. What goes wrong and why? And why did 5.5 work if this didn't? Question 6 ---------- This question is easy to code, but tricky to understand. It shows what is going on with name inheritance and PRIVATE. It is very important to understand the why and not just observe what happens. 6.1 Restart question 5 at 5.4, but declare dp as PRIVATE. I.e. the module now starts: MODULE Lapack USE double PRIVATE :: dp and the main program does NOT have a USE double (i.e. as in 4.3). Why does this not work when 5.4 did? 6.2 Now put the USE double back into the main program. Check that it now works again. Why is this? 6.3 Now replace the USE double in module Lapack by its source form INTEGER, PARAMETER :: dp = SELECTED_REAL_KIND(12) Recompile it and then recompile and test it using the main program. Why does this work if 5.6 didn't?