10 |
--------------------------------------------------------------------------------
/bin/knit_lessons.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Only try running R to translate files if there are some files present.
4 | # The Makefile passes in the names of files.
5 |
6 | if [ $# -eq 2 ] ; then
7 | Rscript -e "source('bin/generate_md_episodes.R')" "$@"
8 | fi
9 |
--------------------------------------------------------------------------------
/exercises/09-functions-subroutines/exercise_program1.f90:
--------------------------------------------------------------------------------
1 | program exercise_program1
2 |
3 | ! Functions and subroutines
4 |
5 | use exercise_module1
6 | implicit none
7 |
8 | print *, "pi: ", pi_gauss_legendre()
9 |
10 | end program exercise_program1
11 |
--------------------------------------------------------------------------------
/exercises/08-modules/program1.f90:
--------------------------------------------------------------------------------
1 | program program1
2 |
3 | use module1
4 | implicit none
5 |
6 | real (kind = mykind) :: a
7 |
8 | a = pi_mykind()
9 |
10 | print *, "Module mykind: ", mykind
11 | print *, "Value of a: ", a
12 |
13 | end program program1
14 |
--------------------------------------------------------------------------------
/_includes/dc/who.html:
--------------------------------------------------------------------------------
1 |
2 | Who:
3 | The course is aimed at graduate students and other researchers.
4 |
5 | You don't need to have any previous knowledge of the tools
6 | that will be presented at the workshop.
7 |
8 |
2 | Who:
3 | The course is aimed at graduate students and other researchers.
4 |
5 | You don't need to have any previous knowledge of the tools
6 | that will be presented at the workshop.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/exercises/01-hello-world/exercise1.f90:
--------------------------------------------------------------------------------
1 | program exercise1
2 |
3 | use, intrinsic :: iso_fortran_env
4 |
5 | print *, "output_unit is: ", output_unit
6 | print *, "error_unit is: ", error_unit
7 | print *, "input_unit is: ", input_unit
8 |
9 | end program exercise1
10 |
--------------------------------------------------------------------------------
/_includes/main_title.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Main title for lesson pages.
3 | {% endcomment %}
4 |
5 | {% include base_path.html %}
6 |
7 |
2 | Who:
3 | The course is for people working in library- and information-related roles.
4 |
5 | You don't need to have any previous knowledge of the tools that
6 | will be presented at the workshop.
7 |
8 |
9 |
--------------------------------------------------------------------------------
/_episodes/22-exercises.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Exercises"
3 | exercises: 60
4 | questions:
5 | - ""
6 | objectives:
7 | - ""
8 | keypoints:
9 | - ""
10 | ---
11 |
12 | We will use the rest of today to work on any exercises from the lessons and the tri-diagonal and Game of Life exercises from Lesson XX.
--------------------------------------------------------------------------------
/_layouts/break.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base
3 | ---
4 | {% include episode_navbar.html episode_navbar_title=true %}
5 |
6 | {% include episode_title.html %}
7 | {% include episode_break.html %}
8 | {{content}}
9 |
10 | {% include episode_navbar.html episode_navbar_title=false %}
11 |
--------------------------------------------------------------------------------
/bin/markdown_ast.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # Use Kramdown parser to produce AST for Markdown document.
4 |
5 | require "kramdown"
6 | require "json"
7 |
8 | markdown = STDIN.read()
9 | doc = Kramdown::Document.new(markdown)
10 | tree = doc.to_hash_a_s_t
11 | puts JSON.pretty_generate(tree)
12 |
--------------------------------------------------------------------------------
/exercises/17-pointers/example1.f90:
--------------------------------------------------------------------------------
1 | program example1
2 |
3 | ! Use of pointer and target
4 |
5 | implicit none
6 |
7 | integer :: datum = 1
8 | integer, pointer :: p => null()
9 |
10 | p => datum
11 | p = 2
12 |
13 | print *, "datum is ", datum
14 |
15 | end program example1
16 |
--------------------------------------------------------------------------------
/_includes/episode_keypoints.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display key points for an episode.
3 | {% endcomment %}
4 |
5 |
Key Points
6 |
7 | {% for keypoint in page.keypoints %}
8 |
{{ keypoint|markdownify }}
9 | {% endfor %}
10 |
11 |
12 |
--------------------------------------------------------------------------------
/exercises/11-characters-strings/example2.f90:
--------------------------------------------------------------------------------
1 | program example2
2 |
3 | implicit none
4 |
5 | character (len = :), allocatable :: string
6 |
7 | string = "ABCD"
8 | print *, "string: ", string, len(string)
9 |
10 | string = "ABCDEFG"
11 | print *, "string: ", string, len(string)
12 |
13 | end program example2
14 |
--------------------------------------------------------------------------------
/_layouts/episode.html:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base
3 | ---
4 | {% include episode_navbar.html episode_navbar_title=true %}
5 |
6 | {% include episode_title.html %}
7 | {% include episode_overview.html %}
8 | {{content}}
9 | {% include episode_keypoints.html %}
10 |
11 | {% include episode_navbar.html episode_navbar_title=false %}
12 |
--------------------------------------------------------------------------------
/exercises/14-namelists/config-full.nml:
--------------------------------------------------------------------------------
1 | &run
2 | name = "TGV" ! Case name
3 | nsteps = 100 ! Number of timesteps
4 | dt = 0.100000001 ! Timestep
5 | /
6 |
7 | &schemes
8 | advection = "upwind" ! Advection scheme
9 | diffusion = "central" ! Diffusion scheme
10 | transient = "RK3" ! Timestepping scheme
11 | /
12 |
--------------------------------------------------------------------------------
/bin/boilerplate/_episodes/01-introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Introduction"
3 | teaching: 0
4 | exercises: 0
5 | questions:
6 | - "Key question (FIXME)"
7 | objectives:
8 | - "First learning objective. (FIXME)"
9 | keypoints:
10 | - "First key point. Brief Answer to questions. (FIXME)"
11 | ---
12 | FIXME
13 |
14 | {% include links.md %}
15 |
16 |
--------------------------------------------------------------------------------
/exercises/09-functions-subroutines/program1.f90:
--------------------------------------------------------------------------------
1 | program program1
2 |
3 | ! Exercise: correct the intent of the dummy argument in the
4 | ! accompanying module1.f90
5 |
6 | use module1
7 | implicit none
8 |
9 | real :: x
10 |
11 | call assign_x(x)
12 | call print_x(x)
13 | call increment_x(x)
14 | call print_x(x)
15 |
16 | end program program1
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Met Office Introduction to Fortran 19 - 21 May 2025
2 |
3 | This repository contains the material for use in the Introduction to Fortran course to be delivered at the Met Office 19 - 21 May 2025. Pushes to the `gh-pages` branch will be reflected in the pages available at [https://epcced.github.io/2025-05-19-MO-Fortran-intro/](https://epcced.github.io/2025-05-19-MO-Fortran-intro/).
4 |
--------------------------------------------------------------------------------
/exercises/01-hello-world/example2.f90:
--------------------------------------------------------------------------------
1 |
2 | ! Formally, the program structure should be...
3 | !
4 | ! [program name]
5 | ! [specification statements]
6 | ! [executable statements]
7 | ! end [program [name]]
8 | !
9 | ! So this is the shortest standard conforming program (not very interesting)
10 | ! We recommend sticking to program ... end program
11 |
12 | end
13 |
--------------------------------------------------------------------------------
/exercises/08-modules/module1.f90:
--------------------------------------------------------------------------------
1 | module module1
2 |
3 | implicit none
4 |
5 | integer, parameter :: mykind = kind(1.d0)
6 |
7 | contains
8 |
9 | function pi_mykind() result(pi)
10 |
11 | ! Return the value of a well-known constant
12 |
13 | real (kind = mykind) :: pi
14 |
15 | pi = 4.0*atan(1.0_mykind)
16 |
17 | end function pi_mykind
18 |
19 | end module module1
20 |
--------------------------------------------------------------------------------
/_includes/figure.html:
--------------------------------------------------------------------------------
1 |
2 | {% if include.url != "" %}
3 |
4 | {% endif %}
5 |
7 | {% if include.url != "" %}
8 |
9 | {% endif %}
10 | {{ include.caption }}
11 |
12 |
--------------------------------------------------------------------------------
/_includes/episode_break.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display a break's timings in a box similar to a learning episode's.
3 | {% endcomment %}
4 |
5 |
Overview
6 |
7 |
8 |
9 | Break: {{ page.break }} min
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/exercises/11-characters-strings/exercise_module1.f90:
--------------------------------------------------------------------------------
1 | module exercise_module1
2 |
3 | ! String functions exercise.
4 | !
5 | ! 1. Write a subroutine string_to_lower_case() to replace the argument
6 | ! 2. Write a function to_lower_case() to return a new string
7 | !
8 | ! See exercise_program1.f90 for a test.
9 |
10 | implicit none
11 | public
12 |
13 | contains
14 |
15 | end module exercise_module1
16 |
--------------------------------------------------------------------------------
/exercises/10-dummy-array-arguments/module1.f90:
--------------------------------------------------------------------------------
1 | module module1
2 |
3 | ! Provides a subroutine to add a to b
4 |
5 | implicit none
6 | public
7 |
8 | contains
9 |
10 | subroutine array_action2(a, b)
11 |
12 | real, dimension(:,:), intent(in) :: a
13 | real, dimension(:,:), intent(inout) :: b
14 |
15 | b(:,:) = b(:,:) + a(:,:)
16 |
17 | end subroutine array_action2
18 |
19 | end module module1
20 |
--------------------------------------------------------------------------------
/exercises/17-pointers/example2.f90:
--------------------------------------------------------------------------------
1 | program example2
2 |
3 | ! Use of associate construct
4 |
5 | implicit none
6 |
7 | real, dimension(7) :: r1 = [ 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0 ]
8 |
9 | associate(p => r1(2::2))
10 | print *, "Pointer section size: ", size(p)
11 | print *, "Pointer section: ", p
12 | p = 0.0
13 | end associate
14 |
15 | print *, "Original at exit ", r1(:)
16 |
17 | end program example2
18 |
--------------------------------------------------------------------------------
/exercises/11-characters-strings/example1.f90:
--------------------------------------------------------------------------------
1 | program example1
2 |
3 | implicit none
4 |
5 | character (len = 20) :: file_stub
6 | character (len = 10) :: file_ext
7 |
8 | file_stub = "filename"
9 | file_ext = "ext"
10 |
11 | print *, "len(file_stub): ", len(file_stub)
12 | print *, "len_trim(file_stub): ", len_trim(file_stub)
13 |
14 | print *, "File name: ", trim(file_stub)//"."//file_ext(1:3)
15 |
16 | end program example1
17 |
--------------------------------------------------------------------------------
/bin/boilerplate/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: lesson
3 | root: . # Is the only page that doesn't follow the pattern /:path/index.html
4 | permalink: index.html # Is the only page that doesn't follow the pattern /:path/index.html
5 | ---
6 | FIXME: home page introduction
7 |
8 |
9 |
10 | {% comment %} This is a comment in Liquid {% endcomment %}
11 |
12 | > ## Prerequisites
13 | >
14 | > FIXME
15 | {: .prereq}
16 |
17 | {% include links.md %}
18 |
--------------------------------------------------------------------------------
/exercises/06-array-expressions/example1.f90:
--------------------------------------------------------------------------------
1 | program example1
2 |
3 | implicit none
4 |
5 | integer, dimension(4, 8) :: a1, a2
6 | integer, dimension(4) :: b1
7 |
8 | a1 = 0
9 | a2 = a1 + 1
10 | a1 = 2*a2
11 |
12 | ! Set b1 to be the first column of a1
13 | b1 = a1
14 |
15 | print *, "b1 is: ", b1
16 |
17 | ! Set b1 to first half of first row of a2()
18 | b1(1:4) = a2(1, 4:4)
19 |
20 | print *, "b1 is: ", b1
21 |
22 | end program example1
23 |
--------------------------------------------------------------------------------
/exercises/11-characters-strings/example3.f90:
--------------------------------------------------------------------------------
1 | program example3
2 |
3 | ! Character parameter array example
4 |
5 | implicit none
6 |
7 | character (len = *), dimension(7), parameter :: days = &
8 | ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", &
9 | "Saturday"]
10 |
11 | integer :: n
12 |
13 | do n = 1, 7
14 | print *, days(n), len(days(n)), len_trim(days(n))
15 | end do
16 |
17 | end program example3
18 |
--------------------------------------------------------------------------------
/exercises/16-data-structures/program1.f90:
--------------------------------------------------------------------------------
1 | program program1
2 |
3 | ! A linear congruential generator
4 | ! See, e.g, https://en.wikipedia.org/wiki/Linear_congruential_generator
5 |
6 | ! Some very bad values might be: my_rng(1, 1, 0, 2147483647)
7 |
8 | use module1
9 | implicit none
10 |
11 | type (my_rng) :: rng = my_rng()
12 | integer :: n
13 |
14 | do n = 1, 6
15 | print *, "Step ", n, my_rng_int(rng)
16 | end do
17 |
18 | end program program1
19 |
--------------------------------------------------------------------------------
/exercises/04-do-statements/example1.f90:
--------------------------------------------------------------------------------
1 | program example1
2 |
3 | ! A simple iteration
4 |
5 | implicit none
6 |
7 | integer :: i = 0
8 |
9 | do
10 | i = i + 1
11 | if (mod(i, 2) == 0) cycle ! go to the next iteration
12 | if (i >= 10) exit ! exit loop completely
13 | print *, "Iteration: ", i
14 | end do
15 |
16 | ! ... control continues here after exit ...
17 | print *, "At end of iteration: ", i
18 |
19 | end program example1
20 |
--------------------------------------------------------------------------------
/exercises/16-data-structures/solutions-2/date_program.f90:
--------------------------------------------------------------------------------
1 | program date_program
2 |
3 | use date_module
4 | implicit none
5 |
6 | type (my_type) :: date
7 |
8 | date%day = 21
9 | date%month = 4
10 | date%year = 2022
11 |
12 | ! Some valid date examples ...
13 |
14 | print *, "List directed date output: ", date
15 | print "(a,dt)", "Default dt format: ", date
16 | print "(a,dt(2,4,5))", "vlist dt format: ", date
17 |
18 | end program date_program
19 |
--------------------------------------------------------------------------------
/exercises/09-functions-subroutines/solutions/solution_program1.f90:
--------------------------------------------------------------------------------
1 | program exercise_program1
2 |
3 | ! Functions and subroutines
4 |
5 | use exercise_module1
6 | implicit none
7 |
8 | integer :: n
9 | real :: fn, pi
10 |
11 | print *, "pi: ", pi_gauss_legendre()
12 |
13 | call pi_gauss_legendre_sub(1, pi)
14 | print *, "pi_1: ", pi
15 |
16 | do n = 1, 12
17 | print *, "n, F_n: ", n, fibonacci(n)
18 | end do
19 |
20 | end program exercise_program1
21 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: "Contributor Code of Conduct"
4 | ---
5 | As contributors and maintainers of this project,
6 | we pledge to follow the [Carpentry Code of Conduct][coc].
7 |
8 | Instances of abusive, harassing, or otherwise unacceptable behavior
9 | may be reported by following our [reporting guidelines][coc-reporting].
10 |
11 | Participants are required to abide by the [ARCHER2 Training Code of Conduct][archer2-tcoc].
12 |
13 | {% include links.md %}
14 |
--------------------------------------------------------------------------------
/exercises/03-if-statements/example1.f90:
--------------------------------------------------------------------------------
1 | program example1
2 |
3 | implicit none
4 |
5 | integer :: i = 1
6 | integer :: j = 2
7 | logical :: condition1
8 | logical :: condition2
9 |
10 | condition1 = (i < j)
11 | condition2 = (i > j)
12 |
13 | if (condition1) then
14 | print *, "The smaller is: i ", i
15 | else if (condition2) then
16 | print *, "The larger is: i ", i
17 | else
18 | print *, "i,j are the same: ", i
19 | end if
20 |
21 | end program example1
22 |
--------------------------------------------------------------------------------
/exercises/02-variables/example1.f90:
--------------------------------------------------------------------------------
1 | program example1
2 |
3 | ! Default numeric types with some initial values
4 |
5 | implicit none
6 |
7 | integer :: i = 1 ! A default integer kind
8 | real :: a = 2.0 ! A default floating point kind
9 | complex :: z = (0.0, 1.0) ! A complex kind with (real-part, imag-part)
10 |
11 | print *, "The value of i: ", i
12 | print *, "The value of a: ", a
13 | print *, "The value of c: ", z
14 |
15 | end program example1
16 |
--------------------------------------------------------------------------------
/exercises/02-variables/exercise2.f90:
--------------------------------------------------------------------------------
1 | program exercise2
2 |
3 | ! Debug this program
4 |
5 | implicit none
6 |
7 | integer, parameter :: nmax = 32 ! A constant
8 | real, parameter :: pi = 4.0*atan(1.e0) ! A well-known constant
9 | complex, parameter :: zi = (0.0, 1.0) ! square root of -1
10 |
11 | nmax = 33
12 |
13 | print *, "The value of nmax: ", nmax
14 | print *, "The value of pi: ", pi
15 | print *, "The value of ci: ", zi
16 |
17 | end program exercise2
18 |
--------------------------------------------------------------------------------
/exercises/04-do-statements/example3.f90:
--------------------------------------------------------------------------------
1 | program example3
2 |
3 | ! Loop trip count: check for each case ...
4 |
5 | implicit none
6 |
7 | integer :: i
8 |
9 | print *, "First loop: 1, 10"
10 | do i = 1, 10
11 | print *, "i is ", i
12 | end do
13 |
14 | print *, "Second loop: 1, 10, -2"
15 | do i = 1, 10, -2
16 | print *, "i is ", i
17 | end do
18 |
19 | print *, "Third loop: 10, 1, -2"
20 | do i = 10, 1, -2
21 | print *, "i is ", i
22 | end do
23 |
24 | end program example3
25 |
--------------------------------------------------------------------------------
/exercises/04-do-statements/example2.f90:
--------------------------------------------------------------------------------
1 | program example2
2 |
3 | ! Example: exit from a nested loop.
4 |
5 | implicit none
6 |
7 | integer :: i = 0
8 |
9 | some_outer_loop: &
10 | do
11 | some_inner_loop: &
12 | do
13 | if (i >= 10) exit some_outer_loop
14 | print *, "Inner iteration after exit ", i
15 | i = i + 1
16 | end do some_inner_loop
17 | print *, "Never get here"
18 | end do some_outer_loop
19 |
20 | print *, "End of iteration"
21 |
22 | end program example2
23 |
--------------------------------------------------------------------------------
/exercises/10-dummy-array-arguments/program1.f90:
--------------------------------------------------------------------------------
1 | program program1
2 |
3 | ! Is there a problem here... if so, where?
4 |
5 | use module1
6 | implicit none
7 | integer, parameter :: imax = 3
8 | integer, parameter :: jmax = 2
9 |
10 | real, dimension(0:imax+1,0:jmax+1) :: a
11 | real, dimension(1:imax, 1:jmax) :: b
12 |
13 | a(1:imax,1:jmax) = 1.0
14 | b(:,:) = 1.0
15 |
16 | call array_action2(a, b)
17 | call array_action2(a(1:imax,1:jmax), b)
18 |
19 | print *, "Values b: ", b(:,:)
20 |
21 | end program program1
22 |
--------------------------------------------------------------------------------
/exercises/18-further-functions/solutions/integral_program.f90:
--------------------------------------------------------------------------------
1 | program integral_program
2 |
3 | use integral_module
4 | implicit none
5 |
6 | ! Quadrature of the function my_cos_sin using n points
7 | ! The answer for [0, pi/2] should be one half
8 |
9 | real, parameter :: pi = 4.0*atan(1.e0)
10 | real :: a = 0.0
11 | real :: b = 0.5*pi
12 | integer :: n
13 |
14 | do n = 1, 3
15 | print *, "Answer: ", 10**n, my_integral(a, b, 10**n, my_cos_sin)
16 | end do
17 |
18 | end program integral_program
19 |
--------------------------------------------------------------------------------
/exercises/21-conjugate-gradient/solutions-2/mm_test.f90:
--------------------------------------------------------------------------------
1 | program mm_test
2 |
3 | ! Test for accompanying module to read a Matrix Market file.
4 |
5 | ! This one is
6 | ! https://math.nist.gov/MatrixMarket/data/Harwell-Boeing/bcsstruc1/bcsstk08.html
7 | ! which needs to be downloaded.
8 |
9 | use mmarket
10 | implicit none
11 |
12 | type (mm_matrix) :: mm
13 | integer :: ierr
14 |
15 | ierr = mm_matrix_from_file("bcsstk08.mtx", mm)
16 | print *, "Matrix nrows, ncols, non-zeros: ", mm%nrows, mm%ncols, mm%nentries
17 |
18 | end program mm_test
19 |
--------------------------------------------------------------------------------
/exercises/01-hello-world/example1.f90:
--------------------------------------------------------------------------------
1 | program hello
2 |
3 | ! Comments are introduced via and exclaimation mark
4 | ! Simple output is via a print statement
5 |
6 | print *, "Hello world"
7 |
8 | ! In general
9 | ! print format, list
10 | !
11 | ! where format can be one of three things
12 | ! a string (a format descriptor)
13 | ! an asterisk list directed i/o "a free format" decided by implementation
14 | ! a label statement label for format defined elsewhere
15 |
16 | ! the list is a comma separated list of items
17 |
18 | end program hello
19 |
--------------------------------------------------------------------------------
/exercises/02-variables/example3.f90:
--------------------------------------------------------------------------------
1 | program example3
2 |
3 | implicit none
4 |
5 | ! Print kind type parameters, and storage size, for different types
6 |
7 | integer, parameter :: my_e_k = kind(1.e0)
8 | integer, parameter :: my_d_k = kind(1.d0)
9 |
10 | real (my_e_k) :: a
11 | real (my_d_k) :: b
12 |
13 | print *, "Kind type parameter for a: ", my_e_k
14 | print *, "Kind type parameter for b: ", my_d_k
15 |
16 | print *, "Storage size(a): ", storage_size(a)
17 | print *, "Storage size(b): ", storage_size(b)
18 |
19 | end program example3
20 |
--------------------------------------------------------------------------------
/exercises/14-namelists/solutions/namelist-write.f90:
--------------------------------------------------------------------------------
1 | program namelist_write
2 |
3 | implicit none
4 |
5 | integer :: nmlunit
6 |
7 | ! Declare variables
8 | character(len=:), allocatable :: name
9 | integer :: nsteps
10 | real :: dt
11 | namelist /run/ name, nsteps, dt
12 |
13 | ! Initialise variables
14 | name = "TGV"
15 | nsteps = 100
16 | dt = 0.1
17 |
18 | ! Write data to namelist
19 | open(newunit = nmlunit, file="config-out.nml", status = "new", action = "write")
20 | write(nmlunit, run)
21 | close(nmlunit)
22 |
23 | end program namelist_write
24 |
--------------------------------------------------------------------------------
/exercises/14-namelists/namelist-read.f90:
--------------------------------------------------------------------------------
1 | program namelist_read
2 |
3 | implicit none
4 |
5 | integer :: nmlunit
6 | character(len=128) :: name
7 | integer :: nsteps
8 | real :: dt
9 | namelist /run/ name, nsteps, dt
10 |
11 | ! Get the run configuration from file
12 | open(newunit = nmlunit, file="config.nml", status = "old", action = "read")
13 | read(nmlunit, run)
14 | close(nmlunit)
15 |
16 | ! Print the run configuration
17 | print *, "Case Name: ", trim(name)
18 | print *, "nSteps: ", nsteps
19 | print *, "Time Step: ", dt
20 |
21 | end program namelist_read
22 |
23 |
--------------------------------------------------------------------------------
/_includes/workshop_calendar.html:
--------------------------------------------------------------------------------
1 | Add to your Google Calendar.
2 |
--------------------------------------------------------------------------------
/_episodes/15-exercise.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Exercises"
3 | teaching: 0
4 | exercises: 60
5 | questions:
6 | - "What are some problems I can work on?"
7 | objectives:
8 | - "Continue to work on exercises from taught material and the larger two problems from yesterday."
9 | keypoints:
10 | - "Gain more experience putting your new knowledge to use."
11 | ---
12 |
13 | We will use the rest of today to work on any of the taught exercises you would
14 | like to spend more time on, as well as the tri-diagonal and Game of Life
15 | exercises from [yesterday afternoon's session]({{ page.root }}{% link
16 | _episodes/07-exercise.md %}).
--------------------------------------------------------------------------------
/exercises/09-functions-subroutines/module1.f90:
--------------------------------------------------------------------------------
1 | module module1
2 |
3 | ! Exercise: correct the intent of the dummy arguments
4 |
5 | implicit none
6 | public
7 |
8 | contains
9 |
10 | subroutine assign_x(x)
11 |
12 | real, intent(in) :: x
13 |
14 | x = 1.0
15 |
16 | end subroutine assign_x
17 |
18 | subroutine print_x(x)
19 |
20 | real, intent(in) :: x
21 |
22 | print *, "The value of x is: ", x
23 |
24 | end subroutine print_x
25 |
26 | subroutine increment_x(x)
27 |
28 | real, intent(in) :: x
29 |
30 | x = x + 1.0
31 |
32 | end subroutine increment_x
33 |
34 | end module module1
35 |
--------------------------------------------------------------------------------
/exercises/11-characters-strings/exercise_program1.f90:
--------------------------------------------------------------------------------
1 | program exercise_program1
2 |
3 | ! String functions test
4 |
5 | use exercise_module1
6 | implicit none
7 |
8 | character (len = *), parameter :: ref = "ABCabc123"
9 | character (len = :), allocatable :: tstring
10 |
11 | tstring = ref
12 | print *, "Input to test 1: ", tstring
13 | call string_to_lower_case(tstring)
14 | print *, "Result of test 1: ", tstring
15 |
16 | tstring = ref
17 | print *, "Input to test 2: ", tstring
18 | tstring = to_lower_case(tstring)
19 | print *, "Result of test 2: ", tstring
20 |
21 | end program exercise_program1
22 |
--------------------------------------------------------------------------------
/exercises/13-IO/program1.f90:
--------------------------------------------------------------------------------
1 | program solution_program
2 |
3 | ! Establish a logical array and write out a suitable pbm file.
4 |
5 | use solution_module
6 | implicit none
7 |
8 | integer, parameter :: n = 49
9 | logical, dimension(n,2*n) :: map
10 |
11 | integer :: i, ierr
12 |
13 | ! Set top row, left column, and the diagonal
14 |
15 | map(:,:) = .false.
16 | map(1,:) = .true.
17 | map(:,1) = .true.
18 |
19 | do i = 1, n
20 | map(i,i) = .true.
21 | end do
22 |
23 | call write_pbm(map, "test49.pbm", ierr)
24 |
25 | print *, "Return value was ", ierr
26 |
27 | end program solution_program
28 |
--------------------------------------------------------------------------------
/exercises/18-further-functions/example1.f90:
--------------------------------------------------------------------------------
1 | program example1
2 |
3 | ! Calling a external function
4 |
5 | ! 1, Add an extern declaration to allow the program to compile
6 | ! 2. Replace the extern declaration by an interface which is
7 | ! consistent with the definition of array_size() as it
8 | ! appears in external.f90. What new error has the interface
9 | ! exposed?
10 |
11 | implicit none
12 |
13 | real, dimension(3,2) :: a
14 |
15 | ! Place an external declaration or interface block (not both) here.
16 |
17 | print *, "The array size is: ", array_size(a), size(a)
18 |
19 | end program example1
20 |
--------------------------------------------------------------------------------
/exercises/11-characters-strings/solutions/solution_program1.f90:
--------------------------------------------------------------------------------
1 | program exercise_program1
2 |
3 | ! String functions test
4 |
5 | use exercise_module1
6 | implicit none
7 |
8 | character (len = *), parameter :: ref = "ABCabc123"
9 | character (len = :), allocatable :: tstring
10 |
11 | tstring = ref
12 | print *, "Input to test 1: ", tstring
13 | call string_to_lower_case(tstring)
14 | print *, "Result of test 1: ", tstring
15 |
16 | tstring = ref
17 | print *, "Input to test 2: ", tstring
18 | tstring = to_lower_case(tstring)
19 | print *, "Result of test 2: ", tstring
20 |
21 | end program exercise_program1
22 |
--------------------------------------------------------------------------------
/exercises/02-variables/example2.f90:
--------------------------------------------------------------------------------
1 | program example2
2 |
3 | ! Use int32 and real64 kind type parameters from iso_fortran_env
4 | ! to determine the precision of variables.
5 |
6 | ! Note that the use statement must be before the implicit none,
7 | ! which should precede the declarations.
8 |
9 | use iso_fortran_env, only : int64, real64
10 | implicit none
11 |
12 | integer (kind = int64) :: i = 100
13 | real (kind = real64) :: a = 1.0
14 | complex (kind = real64) :: z = (0.0, 1.0)
15 |
16 | print *, "The value of i: ", i
17 | print *, "The value of a: ", a
18 | print *, "The value of c: ", z
19 |
20 | end program example2
21 |
--------------------------------------------------------------------------------
/exercises/03-if-statements/example2.f90:
--------------------------------------------------------------------------------
1 | program example2
2 |
3 | ! Some character variables
4 |
5 | implicit none
6 |
7 | character (len = *), parameter :: string1 = "don't" ! 5 characters
8 | character (len = 5) :: string2 = "Don""t" ! 5 characters
9 | character (len = 6) :: string3 = 'don''t' ! 5 characters + blank
10 |
11 | print *, "string1: ", string1
12 | print *, "string2: ", string2
13 | print *, "string3: ", string3
14 |
15 | print *, "Catenated: ", string3//string2//string1
16 | print *, "Substring: ", string2(1:2)
17 | print *, "kind('A'): ", kind('A')
18 |
19 | end program example2
20 |
--------------------------------------------------------------------------------
/_includes/all_keypoints.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display key points of all episodes for reference.
3 | {% endcomment %}
4 |
5 | {% include base_path.html %}
6 |
7 |
Key Points
8 |
9 | {% for episode in site.episodes %}
10 | {% unless episode.break %}
11 |
26 |
--------------------------------------------------------------------------------
/exercises/03-if-statements/exercise1.f90:
--------------------------------------------------------------------------------
1 | program exercise1
2 |
3 | ! Compute the two solutions (say x1, and x2) of
4 | ! a x^2 + b x + c = 0
5 | ! which may be written
6 | ! x = (-b +/- sqrt(b^2 - 4ac))/2a.
7 | !
8 | ! First, use real variables and compute the discriminant
9 | ! b^2 - 4ac
10 | ! and act accordingly.
11 | !
12 | ! Then use complex variables to compute, directly, two complex roots
13 | ! to check your answer for (x1, x2).
14 | !
15 | ! Some values might be
16 | ! a = 1.0, b = 5.0, c = 6.0 (=> two real roots)
17 | ! a = 2.0, b = 1.0, c = 5.0/8.0 (=> two complex roots)
18 | ! a = 4.0, b = -8.0, c = 4.0 (=> two equal roots)
19 |
20 | implicit none
21 |
22 | end program exercise1
23 |
--------------------------------------------------------------------------------
/bin/test_lesson_check.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import unittest
4 |
5 | import lesson_check
6 | import util
7 |
8 |
9 | class TestFileList(unittest.TestCase):
10 | def setUp(self):
11 | self.reporter = util.Reporter() # TODO: refactor reporter class.
12 |
13 | def test_file_list_has_expected_entries(self):
14 | # For first pass, simply assume that all required files are present
15 | all_filenames = [filename.replace('%', '')
16 | for filename in lesson_check.REQUIRED_FILES]
17 |
18 | lesson_check.check_fileset('', self.reporter, all_filenames)
19 | self.assertEqual(len(self.reporter.messages), 0)
20 |
21 |
22 | if __name__ == "__main__":
23 | unittest.main()
24 |
--------------------------------------------------------------------------------
/exercises/14-namelists/namelist-complex.f90:
--------------------------------------------------------------------------------
1 | module types
2 |
3 | implicit none
4 |
5 | type mytype
6 | integer :: a
7 | real :: b
8 | end type mytype
9 |
10 | end module types
11 |
12 | program namelist_complex
13 |
14 | use types
15 |
16 | implicit none
17 |
18 | integer :: nmlunit
19 |
20 | integer, dimension(5) :: a
21 | type(mytype) :: b
22 | namelist /comp/ a, b
23 |
24 | integer :: i
25 |
26 | ! Initialise variables
27 | do i = 1, 5
28 | a(i) = i
29 | end do
30 | b%a = 42
31 | b%b = 3.14
32 |
33 | ! Write data to namelist
34 | open(newunit = nmlunit, file="complex.nml", status = "new", action = "write")
35 | write(nmlunit, comp)
36 | close(nmlunit)
37 |
38 | end program namelist_complex
39 |
40 |
--------------------------------------------------------------------------------
/_includes/javascript.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | JavaScript used in lesson and workshop pages.
3 | {% endcomment %}
4 |
5 |
6 |
7 |
15 |
--------------------------------------------------------------------------------
/_includes/dc/intro.html:
--------------------------------------------------------------------------------
1 |
2 | Data Carpentry
3 | aims to help researchers get their work done
4 | in less time and with less pain
5 | by teaching them basic research computing skills.
6 | This hands-on workshop will cover basic concepts and tools,
7 | including program design, version control, data management,
8 | and task automation.
9 | Participants will be encouraged to help one another
10 | and to apply what they have learned to their own research problems.
11 |
19 |
--------------------------------------------------------------------------------
/exercises/16-data-structures/module1.f90:
--------------------------------------------------------------------------------
1 | module module1
2 |
3 | ! A simple linear congruential generator
4 |
5 | use iso_fortran_env
6 | implicit none
7 |
8 | type, public :: my_rng
9 | integer (int64) :: a = 45991
10 | integer (int32) :: s = 1
11 | integer (int64) :: c = 0
12 | integer (int64) :: m = 2147483647
13 | end type my_rng
14 |
15 | contains
16 |
17 | function my_rng_int(rng) result(inext)
18 |
19 | ! Update the state and return the new value
20 |
21 | type (my_rng), intent(inout) :: rng
22 | integer (int32) :: inext
23 |
24 | integer (int64) :: s
25 |
26 | s = int(rng%s, int64)
27 | rng%s = int(mod(rng%a*s + rng%c, rng%m), int32)
28 | inext = rng%s
29 |
30 | end function my_rng_int
31 |
32 | end module module1
33 |
--------------------------------------------------------------------------------
/_includes/sc/intro.html:
--------------------------------------------------------------------------------
1 |
2 | Software Carpentry
3 | aims to help researchers get their work done
4 | in less time and with less pain
5 | by teaching them basic research computing skills.
6 | This hands-on workshop will cover basic concepts and tools,
7 | including program design, version control, data management,
8 | and task automation.
9 | Participants will be encouraged to help one another
10 | and to apply what they have learned to their own research problems.
11 |
19 |
--------------------------------------------------------------------------------
/exercises/21-conjugate-gradient/cgradient.f90:
--------------------------------------------------------------------------------
1 | module cgradient
2 |
3 | ! Conjugate gradient example
4 | ! We we use the real kind k_kind
5 |
6 | implicit none
7 |
8 | integer, parameter :: k_real = kind(1.e0)
9 |
10 | contains
11 |
12 | subroutine cg_solve(a, b, tol, x, ierr)
13 |
14 | ! The initial guess x will be replaced by the solution on exit
15 |
16 | real (k_real), dimension(:,:), intent(in) :: a ! matrix
17 | real (k_real), dimension(:), intent(in) :: b ! rhs
18 | real (k_real), intent(in) :: tol ! tolerance
19 | real (k_real), dimension(:), intent(inout) :: x
20 | integer, intent(out) :: ierr
21 |
22 | ! Implement your solver here.
23 |
24 | end subroutine cg_solve
25 |
26 | end module cgradient
27 |
--------------------------------------------------------------------------------
/exercises/02-variables/exercise3.f90:
--------------------------------------------------------------------------------
1 | program exercise3
2 |
3 | ! Compute an approximation to pi.
4 |
5 | ! An approximation using the Gauss-Legendre algorithm
6 | ! See, e.g., https://en.wikipedia.org/wiki/Gauss-Legendre_algorithm
7 | !
8 | ! If we initialise:
9 | !
10 | ! a_0 = 1
11 | ! b_0 = 1/sqrt(2)
12 | ! t_0 = 1/4
13 | ! p_0 = 1
14 | !
15 | ! (in general, a_n etc, with n = 0), then the next terms in the series
16 | ! can be computed as:
17 | !
18 | ! a_{n+1} = (a_n + b_n)/2
19 | ! b_{n+1} = sqrt(a_n b_n)
20 | ! t_{n+1} = t_n - p_n (a_n - a_{n+1})^2 with p_{n+1} = 2p_n
21 | !
22 | ! then
23 | !
24 | ! pi_n \approx (a_n + b_n)^2/4t_n
25 | !
26 | ! Compute the first two approximations pi_0 and pi_1.
27 |
28 | implicit none
29 |
30 | end program exercise3
31 |
--------------------------------------------------------------------------------
/exercises/06-array-expressions/exercise2.f90:
--------------------------------------------------------------------------------
1 | program exercise2
2 |
3 | ! A program to identify prime numbers (<= nmax = 120) via the Sieve
4 | ! of Eratosthenses.
5 |
6 | ! See, e.g., https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
7 | !
8 | ! Define a logical array to indicate where relevant integers are
9 | ! prime.
10 | !
11 | ! Implement the sieve to set appropriate values in the logical array
12 | ! using the algorithm described at the reference above.
13 | !
14 | ! Try using loops first; where could you then introduce array
15 | ! constructs?
16 | ! Hint 2. You may need an additional integer array to use array constructs.
17 | !
18 | ! Count how many prime numbers you have. Check your results.
19 | !
20 | ! Is one version any clearer than the other?
21 |
22 | end program exercise2
23 |
--------------------------------------------------------------------------------
/setup.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: page
3 | title: Setup
4 | ---
5 |
6 | Please try to complete the following setup tasks ahead of the lesson.
7 |
8 | ## Create appropriate SAFE and ARCHER2 machine accounts
9 |
10 | Course attendees should have received instructions on how to set up an ARCHER2 [SAFE](https://safe.epcc.ed.ac.uk/) account.
11 | Details are available in the [ARCHER2 documentation][archer2-quickstart].
12 |
13 | You will firstly create a SAFE account. The [SAFE](https://safe.epcc.ed.ac.uk/) is used to manage ARCHER2 projects and accounts. Once you have a SAFE account, you will then be able to request an account on ARCHER2 itself. (If you already have a SAFE or ARCHER2 machine account, you may reuse those.)
14 |
15 | Any problems encountered will be addressed as the first part of the course.
16 |
17 |
18 | {% include links.md %}
19 |
--------------------------------------------------------------------------------
/exercises/08-modules/solutions/solution_module.f90:
--------------------------------------------------------------------------------
1 | module solution_module
2 |
3 | ! Module version of the Gauss-Legendre evaluation of pi
4 |
5 | implicit none
6 | public
7 |
8 | integer, parameter :: kp = kind(1.d0)
9 |
10 | contains
11 |
12 | function pi_gauss_legendre() result(pi)
13 |
14 | integer, parameter :: nmax = 10
15 |
16 | real (kp) :: pi
17 |
18 | real (kp) :: a, an, b, t, p
19 | integer :: n
20 |
21 | ! Initial values, and iterate ...
22 | a = 1.0_kp
23 | b = 1.0/sqrt(2.0_kp)
24 | t = 0.25_kp
25 | p = 1.0_kp
26 |
27 | do n = 1, nmax
28 | an = a
29 | a = (an + b)/2.0
30 | b = sqrt(an*b)
31 | t = t - p*(an - a)**2
32 | p = 2.0*p
33 | end do
34 |
35 | pi = (a + b)**2/(4.0*t)
36 |
37 | end function pi_gauss_legendre
38 |
39 | end module solution_module
40 |
--------------------------------------------------------------------------------
/_includes/workshop_footer.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Footer for a standard workshop.
3 | {% endcomment %}
4 |
27 |
--------------------------------------------------------------------------------
/exercises/21-conjugate-gradient/solutions-1/cg_test.f90:
--------------------------------------------------------------------------------
1 | program cg_test
2 |
3 | ! Conjugate gradient test problem
4 |
5 | use cgradient
6 | implicit none
7 |
8 | integer, parameter :: nmax = 4
9 |
10 | real (k_real), dimension(nmax, nmax) :: a
11 | real (k_real), dimension(nmax) :: b
12 | real (k_real), dimension(nmax) :: x
13 | real (k_real) :: tol = 0.0001
14 | integer :: ierr
15 |
16 | ! a must be symmetric
17 | a(1,:) = [ 4.0, 1.0, 0.0, 0.0 ]
18 | a(2,:) = [ 1.0, 4.0, 1.0, 0.0 ]
19 | a(3,:) = [ 0.0, 1.0, 4.0, 1.0 ]
20 | a(4,:) = [ 0.0, 0.0, 1.0, 4.0 ]
21 |
22 | b(:) = [ 1.0, 4.0, 5.0, 6.0 ]
23 |
24 | ! initial guess
25 | x(:) = 1.0
26 |
27 | call cg_solve(a, b, tol, x, ierr)
28 |
29 | print *, "ierr: ", ierr
30 | print *, "Solution ", x(:)
31 | print *, "Check b: ", matmul(a, x)
32 |
33 | end program cg_test
34 |
--------------------------------------------------------------------------------
/_includes/lc/intro.html:
--------------------------------------------------------------------------------
1 |
2 | Library Carpentry
3 | is made by people working in library- and information-related roles to help you:
4 |
5 |
6 |
automate repetitive, boring, error-prone tasks
7 |
create, maintain and analyze sustainable and reusable data
8 |
work effectively with IT and systems colleagues
9 |
better understand the use of software in research
10 |
and much more...
11 |
12 |
13 |
14 | Library Carpentry introduces you to the fundamentals of computing
15 | and provides you with a platform for further self-directed learning.
16 | For more information on what we teach and why, please see our paper
17 | "Library Carpentry: software skills training for library professionals".
18 |
19 |
20 |
--------------------------------------------------------------------------------
/exercises/18-further-functions/example3.f90:
--------------------------------------------------------------------------------
1 | program example3
2 |
3 | ! Polymorphism logical and inter image arrays
4 |
5 | use pbm_image
6 | implicit none
7 |
8 | integer, parameter :: n = 49
9 | logical, dimension(n,2*n) :: map
10 | integer, dimension(n,2*n) :: imap
11 |
12 | integer :: i, ierr
13 |
14 | ! Set top row, left column, and the diagonal
15 |
16 | map(:,:) = .false.
17 | map(1,:) = .true.
18 | map(:,1) = .true.
19 |
20 | do i = 1, n
21 | map(i,i) = .true.
22 | end do
23 |
24 | call write_pbm(map, "logical49.pbm", ierr)
25 |
26 | print *, "Return value was ", ierr
27 |
28 | ! Integer version
29 |
30 | where (map(:,:) .eqv. .true.)
31 | imap(:,:) = 0
32 | elsewhere
33 | imap(:,:) = -1
34 | end where
35 |
36 | call write_pbm(imap, "integer49.pbm", ierr)
37 |
38 | print *, "Return value was ", ierr
39 |
40 | end program example3
41 |
--------------------------------------------------------------------------------
/exercises/01-hello-world/example3.f90:
--------------------------------------------------------------------------------
1 | program hello_write
2 |
3 | ! A use statement imports public symbols from the "iso_fortran_env"
4 | ! module. This is an "intrinsic" module which must be provided
5 | ! by the implementation.
6 |
7 | ! One can limit the symbols actually imported via the "only" clause.
8 | ! Here we want "output_unit"; there are also (almost other things)
9 | ! "input_unit" and "error_unit".
10 |
11 | ! See e.g., https://fortranwiki.org/fortran/show/iso_fortran_env
12 |
13 | use iso_fortran_env, only : output_unit
14 |
15 | write (output_unit, *) "Hello world"
16 |
17 | ! The write statement here has two arguments in parenthesis
18 | ! stdout the "unit number" here the standard output
19 | ! an asterisk again indicating a free format
20 |
21 | ! You may sometimes see ...
22 |
23 | write (unit = output_unit, fmt = *) "Hello again"
24 |
25 | end program hello_write
26 |
--------------------------------------------------------------------------------
/_includes/life_cycle.html:
--------------------------------------------------------------------------------
1 |
2 | {% if site.life_cycle == "pre-alpha" %}
3 |
4 |
5 |
6 | This lesson is still being designed and assembled (Pre-Alpha version)
7 |
24 | This lesson is being piloted (Beta version)
25 |
26 |
27 |
28 | {% elsif site.life_cycle == "stable" %}
29 |
30 | {% comment %}
31 | We don't do anything special for now
32 | {% endcomment %}
33 |
34 | {% endif %}
35 |
--------------------------------------------------------------------------------
/_includes/episode_overview.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Display an episode's timings and learning objectives.
3 | {% endcomment %}
4 |
5 |
Overview
6 |
7 |
8 |
9 | Teaching: {{ page.teaching }} min
10 |
11 | Exercises: {{ page.exercises }} min
12 |
13 |
14 | Questions
15 |
16 | {% for question in page.questions %}
17 |
{{ question|markdownify }}
18 | {% endfor %}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 | Objectives
28 |
29 | {% for objective in page.objectives %}
30 |
{{ objective|markdownify }}
31 | {% endfor %}
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/_includes/workshop_ad.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | Advertising box at the top of a workshop website home page.
3 | {% endcomment %}
4 |
5 |
6 |
7 |
{{page.venue}}
8 |
9 |
10 |
{{page.humandate}}
11 |
{% if page.humantime %}{{page.humantime}}{% endif %}
29 | {% if page.next.url %}
30 | next episode
31 | {% else %}
32 | lesson home
33 | {% endif %}
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/exercises/02-variables/exercise4.f90:
--------------------------------------------------------------------------------
1 | program exercise4
2 |
3 | ! Compute an approximation to the conductance of a narrow channel.
4 |
5 | ! The steady volume flux (volume flow rate) Q in a rectangular
6 | ! capillary of cross section width x height 2b x 2c (with 2b > 2c)
7 | ! we can write:
8 | !
9 | ! Q = -C (dp/dx) / eta
10 | !
11 | ! with dp/dx the pressure gradient and eta the dynamic viscosity.
12 | ! One can define a viscosity-independent conductance C
13 | !
14 | ! C = (4/3) b c^3 [ 1 - 6(c/b) \sum_k tanh (a_k b/c)/a_k^5 ]
15 | !
16 | ! where a_k = (2k - 1) pi/2 and the sum is k = 1, ..., \inf.
17 | !
18 | ! E.g. T. Papanastasiou, G. Georiou, and A. Alexandrou,
19 | ! "Viscous Fluid Flow" CRC Press, Boca Raton, Florida (2000).
20 |
21 | ! Exercise
22 | ! Compute the first term in the series (i.e., k = 1):
23 | !
24 | ! C_1 = (4/3) b c^3 [ 1 - 6(c/b) tanh(a_k b/c) / a_k^5 ]
25 | !
26 | ! We will use the sample values w = 62, h = 30.
27 | !
28 | ! You will need the intrinsic function tanh() for hyperbolic tangent.
29 | !
30 | ! Your result should be in the region of 97277.88 ( the exact figure
31 | ! depending on precision).
32 |
33 | ! Try for both real32 and real64.
34 | ! Does your compiler support kind real128?
35 |
36 |
37 | ! Some appropriate output might be ...
38 | ! print *, "Value of w: ", w
39 | ! print *, "Value of h: ", h
40 | ! print *, "Value of pi: ", pi
41 | ! print *, "Approximation is: ", conductance
42 |
43 | end program exercise4
44 |
--------------------------------------------------------------------------------
/exercises/10-dummy-array-arguments/exercise.f90:
--------------------------------------------------------------------------------
1 | program exercise
2 |
3 | ! Tri-diagonal matrix problem via Thomas' algorithm
4 | ! See https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm
5 |
6 | ! The following values are used as a test:
7 | ! a = [1.0, 1.0, 1.0] - lower diagonal
8 | ! b = [4.0, 4.0, 4.0, 4.0] - diagonal
9 | ! c = [2.0, 2.0, 2.0] - upper diagonal
10 | ! d = [1.0, 4.0, 5.0, 6.0] - rhs
11 | ! which should give a solution approx. x = [-0.195, 0.890, 0.317, 1.42]
12 |
13 |
14 | use iso_fortran_env
15 | implicit none
16 |
17 | integer, parameter :: mykind = real32
18 | integer, parameter :: nmax = 4
19 |
20 | real (mykind), dimension(nmax) :: b = [4.0, 4.0, 4.0, 4.0]
21 | real (mykind), dimension(2:nmax) :: a = [1.0, 1.0, 1.0]
22 | real (mykind), dimension(1:nmax-1) :: c = [2.0, 2.0, 2.0]
23 | real (mykind), dimension(nmax) :: d = [1.0, 4.0, 5.0, 6.0]
24 | real (mykind), dimension(nmax) :: x
25 |
26 | real (mykind) :: w
27 | integer :: i
28 |
29 | ! Set up the matrix here: all elements; diagonal elements, then
30 | ! off-diagonal elements
31 |
32 | ! Solve via Thomas' algorithm
33 | ! Note b(:) and d(:) are destroyed
34 |
35 | do i = 2, nmax
36 | w = a(i) / b(i-1)
37 | b(i) = b(i) - w*c(i-1)
38 | d(i) = d(i) - w*d(i-1)
39 | end do
40 |
41 | x(:) = d(:)/b(:)
42 |
43 | do i = nmax-1, 1, -1
44 | x(i) = (d(i) - c(i)*x(i+1))/b(i)
45 | end do
46 |
47 | print *, "Solution ", x(:)
48 |
49 | end program exercise
50 |
--------------------------------------------------------------------------------
/exercises/06-array-expressions/solutions/solution.f90:
--------------------------------------------------------------------------------
1 | program exercise2
2 |
3 | ! A program to identify prime numbers (<= nmax = 120) via the Sieve
4 | ! of Eratosthenses.
5 |
6 | ! See, e.g., https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
7 | !
8 | ! Define a logical array to indicate where relevant integers are
9 | ! prime.
10 | !
11 | ! Implement the sieve to set appropriate values in the logical array
12 | ! using the algorithm described at the reference above.
13 | !
14 | ! Try using loops first; where could you then introduce array
15 | ! constructs?
16 | ! Hint. You will need an additional integer array to hold the values
17 | ! themselves in order to use array constructs.
18 | !
19 | ! Count how many prime numbers you have. Check your results.
20 | !
21 | ! Is one version any clearer than the other?
22 |
23 | implicit none
24 |
25 | integer, parameter :: nmax = 120
26 | integer, dimension(2:nmax) :: ia
27 | logical, dimension(2:nmax) :: isprime
28 |
29 | integer :: n, p
30 |
31 | do n = 2, nmax
32 | ia(n) = n
33 | isprime(n) = .true.
34 | end do
35 |
36 | do p = 2, nmax
37 | do n = 2*p, nmax
38 | if (mod(n,p) == 0) isprime(n) = .false.
39 | end do
40 | ! One could use an array construct...
41 | !where (mod(ia(2*p:), p) == 0)
42 | ! isprime(2*p:) = .false.
43 | !end where
44 | end do
45 |
46 | ! Results
47 |
48 | do n = 2, nmax
49 | print *, "n is prime: ", ia(n), isprime(n)
50 | end do
51 |
52 | print *, "Number of primes: ", count(isprime)
53 |
54 | end program exercise2
55 |
--------------------------------------------------------------------------------
/exercises/16-data-structures/exercise_module.f90:
--------------------------------------------------------------------------------
1 | module exercise_module
2 |
3 | ! Tri-diagonal matrix problem via Thomas' algorithm
4 | ! See https://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm
5 |
6 | use iso_fortran_env
7 | implicit none
8 |
9 | integer, parameter :: mykind = real32
10 |
11 | contains
12 |
13 | subroutine tridiagonal_solve(b, a, c, rhs, x)
14 |
15 | ! Routine to solve system for
16 | ! b(1:nmax) diagonal elements
17 | ! a(2:nmax) lower diagonal elements
18 | ! c(1:nmax-1) upper diagonal elements
19 | ! rhs(1:nmax) right-hand side
20 | ! x(1:nmax) solution on exit
21 |
22 | real (mykind), dimension(1:), intent(in) :: b
23 | real (mykind), dimension(2:), intent(in) :: a
24 | real (mykind), dimension(1:), intent(in) :: c
25 | real (mykind), dimension(1:), intent(in) :: rhs
26 | real (mykind), dimension(1:), intent(out) :: x
27 |
28 | real (mykind), dimension(size(b)) :: blocal ! local copy of b
29 | real (mykind), dimension(size(b)) :: rlocal ! local copy of rhs
30 |
31 | integer :: nmax
32 | integer :: i
33 | real (mykind) :: w
34 |
35 | nmax = size(b)
36 | blocal(1:nmax) = b(1:nmax)
37 | rlocal(1:nmax) = rhs(1:nmax)
38 |
39 | ! Solve via Thomas' algorithm
40 |
41 | do i = 2, nmax
42 | w = a(i) / blocal(i-1)
43 | blocal(i) = blocal(i) - w*c(i-1)
44 | rlocal(i) = rlocal(i) - w*rlocal(i-1)
45 | end do
46 |
47 | x(:) = rlocal(:)/blocal(:)
48 |
49 | do i = nmax-1, 1, -1
50 | x(i) = (rlocal(i) - c(i)*x(i+1))/blocal(i)
51 | end do
52 |
53 | end subroutine tridiagonal_solve
54 |
55 | end module exercise_module
56 |
--------------------------------------------------------------------------------
/exercises/06-array-expressions/exercise1.f90:
--------------------------------------------------------------------------------
1 | program exercise1
2 |
3 | ! Here's a version of the program that computes the two roots of
4 | ! a x^2 + b x + c = 0
5 | ! as real numbers, and then as complex numbers.
6 | !
7 | ! Make sure you can replace the two real variable roots (x1r, x1i) and
8 | ! (x2r, x2i) by two arrays of extent 2, one for each root. Use array
9 | ! constructors to combine real and imaginary parts in the if blocks.
10 | !
11 | ! Replace the separate complex roots z1 and z2 by a single array.
12 | !
13 | ! Some values for (a,b,c) might be
14 | ! a = 1.0, b = 5.0, c = 6.0 (=> two real roots)
15 | ! a = 2.0, b = 1.0, c = 5.0/8.0 (=> two complex roots)
16 | ! a = 4.0, b = -8.0, c = 4.0 (=> two equal roots)
17 |
18 | implicit none
19 |
20 | real :: a = 1.0, b = 5.0, c = 6.0
21 | real :: d
22 |
23 | real, dimension(2) :: x1
24 | real, dimension(2) :: x2
25 |
26 | complex, dimension(2) :: z
27 | complex :: zd
28 |
29 | d = b*b - 4.0*a*c
30 |
31 | if (d > 0.0) then
32 | print *, "Two real roots"
33 | x1(1:2) = (/ (-b + sqrt(d))/(2.0*a), 0.0 /)
34 | x2(1:2) = (/ (-b - sqrt(d))/(2.0*a), 0.0 /)
35 | else if (d < 0.0) then
36 | print *, "Two complex roots"
37 | x1(1:2) = (/ -b/(2.0*a), +sqrt(-d)/(2.0*a) /)
38 | x2(1:2) = (/ -b/(2.0*a), -sqrt(-d)/(2.0*a) /)
39 | else
40 | print *, "Two equal roots"
41 | x1(1:2) = [ -b/(2.0*a) , 0.0 ]
42 | x2(1:2) = x1(1:2)
43 | end if
44 |
45 | print *, "Real values x1 = ", x1
46 | print *, "Real values x2 = ", x2
47 |
48 | ! Use complex numbers
49 |
50 | zd = cmplx(d)
51 | z(1) = (-b + sqrt(zd))/(2.0*a)
52 | z(2) = (-b - sqrt(zd))/(2.0*a)
53 | print *, "Complex z1 = ", z(1)
54 | print *, "Complex z2 = ", z(2)
55 |
56 | end program exercise1
57 |
--------------------------------------------------------------------------------
/exercises/04-do-statements/exercise2.f90:
--------------------------------------------------------------------------------
1 | program exercise2
2 |
3 | ! Compute an approximation to the conductance of a narrow channel.
4 |
5 | ! The steady volume flux (volume flow rate) Q in a rectangular
6 | ! capillary of cross section width x height 2b x 2c (with 2b > 2c)
7 | ! we can write:
8 | !
9 | ! Q = -C (dp/dx) / eta
10 | !
11 | ! with dp/dx the pressure gradient and eta the dynamic viscosity.
12 | ! One can define a viscosity-independent conductance C
13 | !
14 | ! C = (4/3) b c^3 [ 1 - 6(c/b) \sum_k tanh (a_k b/c)/a_k^5 ]
15 | !
16 | ! where a_k = (2k - 1) pi/2 and the sum is k = 1, ..., \inf.
17 | !
18 | ! E.g. T. Papanastasiou, G. Georiou, and A. Alexandrou,
19 | ! "Viscous Fluid Flow" CRC Press, Boca Raton, Florida (2000).
20 |
21 | ! Exercise
22 | ! Use a loop to compute a fixed number of terms in the sum over
23 | ! index k. Convergence may be rather slow (check by printing out
24 | ! the current value every 20 iterations.
25 | !
26 | ! We will use the sample values w = 62, h = 30. The template below
27 | ! computes only the first term k = 1.
28 |
29 |
30 | use iso_fortran_env
31 | implicit none
32 |
33 | integer, parameter :: kp = real64
34 |
35 | real (kp), parameter :: pi = 4.0*atan(1.0)
36 | real (kp), parameter :: w = 62.0
37 | real (kp), parameter :: h = 30.0
38 |
39 | real (kp) :: a, b, c
40 | real (kp) :: conductance
41 |
42 | a = 0.5*pi
43 | b = 0.5*w
44 | c = 0.5*h
45 |
46 | ! First term only
47 | conductance = (4.0/3.0)*b*(c**3)*(1.0 - 6.0*(c/b)*tanh(a*b/c)/a**5)
48 |
49 | ! Some appropriate output might be ...
50 | print *, "Value of w: ", w
51 | print *, "Value of h: ", h
52 | print *, "Value of pi: ", pi
53 | print *, "Approximation is: ", conductance
54 |
55 | end program exercise2
56 |
--------------------------------------------------------------------------------
/_includes/gh_variables.html:
--------------------------------------------------------------------------------
1 | {% comment %}
2 | When rendering websites locally, `site.github.url` doesn't get resolved properly
3 | unless a GitHub Personal Access Token is set up and available in the
4 | environment. This leads to warnings and errors when trying to serve the site
5 | locally. To work around this, we use the `jekyll.environment` variable which is
6 | set to `development` when rendering the site locally, and set to `production` on
7 | GitHub where `site.github.url` is defined.
8 | {% endcomment %}
9 |
10 | {% if jekyll.environment == "production" %}
11 |
12 | {% comment %}
13 | First, get the name of the repository
14 | {% endcomment %}
15 | {% assign repo_name = site.github.repository_name %}
16 |
17 | {% comment %}
18 | `site.github.public_repositories` contains comprehensive information for all public repositories for the organization. We use `where` to extract the part
19 | of the metadata that is relevant to the present repository.
20 | {% endcomment %}
21 | {% assign repo_info = site.github.public_repositories | where: "name", repo_name %}
22 |
23 | {% comment %}
24 | Now, we can extract the default branch for the repo
25 | {% endcomment %}
26 | {% assign default_branch = repo_info[0].default_branch %}
27 |
28 | {% comment %}
29 | Other variables requested by the template
30 | {% endcomment %}
31 | {% assign repo_url = site.github.repository_url %}
32 | {% assign search_domain_url = site.github.url %}
33 | {% assign project_title = site.github.project_title %}
34 | {% assign source_branch = site.github.source.branch %}
35 |
36 | {% elsif jekyll.environment == "development" %}
37 |
38 | {% assign repo_name = "" %}
39 | {% assign repo_url = "" %}
40 | {% assign default_branch = "" %}
41 | {% assign search_domain_url = "" %}
42 | {% assign project_title = "" %}
43 | {% assign source_branch = "" %}
44 |
45 | {% endif %}
46 |
--------------------------------------------------------------------------------
/_layouts/base.html:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 | {% include base_path.html %}
4 | {% include gh_variables.html %}
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | {% include favicons.html %}
21 |
22 |
23 |
24 |
28 | {{ site.title }}{% if page.title %}: {{ page.title }}{% endif %}
29 |
30 |
31 |
32 | {% include life_cycle.html %}
33 |
34 |
25 | {% for episode in site.episodes %}
26 | {% if episode.start %} {% comment %} Starting a new day? {% endcomment %}
27 | {% assign day = day | plus: 1 %}
28 | {% if day > 1 %} {% comment %} If about to start day 2 or later, show finishing time for previous day {% endcomment %}
29 | {% assign hours = current | divided_by: 60 %}
30 | {% assign minutes = current | modulo: 60 %}
31 |
32 | {% if multiday %}
{% endif %}
33 |
{% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }}
34 |
Finish
35 |
36 |
37 | {% endif %}
38 | {% assign current = site.start_time %} {% comment %}Re-set start time of this episode to general daily start time {% endcomment %}
39 | {% endif %}
40 | {% assign hours = current | divided_by: 60 %}
41 | {% assign minutes = current | modulo: 60 %}
42 |
43 | {% if multiday %}
{% if episode.start %}Day {{ day }}{% endif %}
{% endif %}
44 |
{% if hours < 10 %}0{% endif %}{{ hours }}:{% if minutes < 10 %}0{% endif %}{{ minutes }}
The Carpentries comprises
13 | Software Carpentry, Data Carpentry, and Library Carpentry communities of Instructors, Trainers,
14 | Maintainers, helpers, and supporters who share a mission to teach
15 | foundational coding and data science skills to researchers and people
16 | working in library- and information-related roles. In January,
17 | 2018, The Carpentries was formed by the merger of Software Carpentry and
18 | Data Carpentry. Library Carpentry became an official Carpentries Lesson Program in November 2018.
19 |
20 |
While individual lessons and workshops continue to be run under each
21 | lesson project, The Carpentries provide overall staffing and governance, as
22 | well as support for assessment, instructor training and mentoring.
23 | Memberships are joint, and the Carpentries project maintains a shared Code
24 | of Conduct. The Carpentries is a fiscally sponsored project of Community
25 | Initiatives, a registered 501(c)3 non-profit based in California, USA.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Since 1998, Software Carpentry has
34 | been teaching researchers across all disciplines the foundational coding
35 | skills they need to get more done in less time and with less pain. Its
36 | volunteer instructors have run hundreds of events for thousands of learners
37 | around the world. Now that all research involves some degree of
38 | computational work, whether with big data, cloud computing, or simple task
39 | automation, these skills are needed more than ever.
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
Data Carpentry develops and teaches
49 | workshops on the fundamental data skills needed to conduct research. Its
50 | target audience is researchers who have little to no prior computational
51 | experience, and its lessons are domain specific, building on learners'
52 | existing knowledge to enable them to quickly apply skills learned to their
53 | own research. Data Carpentry workshops take researchers through the entire
54 | data life cycle.
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
Library Carpentry develops lessons and
64 | teaches workshops for and with people working in library- and
65 | information-related roles. Its goal is to create an on-ramp to empower this
66 | community to use software and data in their own work, as well as be
67 | advocates for and train others in efficient, effective and reproducible data
68 | and software practices.