diff --git a/pages/how-to/compute-pi-openmp.md b/pages/how-to/compute-pi-openmp.md new file mode 100644 index 000000000..e100309fd --- /dev/null +++ b/pages/how-to/compute-pi-openmp.md @@ -0,0 +1,51 @@ +# Computing PI with OpenMP + +This is a simple example of how to use OpenMP with fpm. +It is an adapted version of the OpenMP example that can be found +[here](https://github.com/gjbex/Fortran-MOOC/blob/master/source_code/computing_pi/compute_pi_omp.f90) under a +[CC-BY-4.0](https://github.com/gjbex/Fortran-MOOC/blob/master/LICENSE) license. + +The code approximates the value of PI by performing parallelized numerical +integration over a quarter of the unit circle. +The code is structured as follows: + +```{literalinclude} ../../src/how-to/compute-pi-openmp/app/main.f90 +:language: fortran +:caption: app/main.f90 +``` + +## Using OpenMP as a dependency + +To use OpenMP in your project, you need to add the `openmp` dependency to your `fpm.toml` file: + +```{literalinclude} ../../src/how-to/compute-pi-openmp/fpm.toml +:language: toml +:caption: fpm.toml +:emphasize-lines: 4-5 +``` + +OpenMP is a _built-in dependency_ (i.e. metapackage), which means the above +syntax needs to be used. To find out more about metapackages, see [](../spec/metapackages). + +## Building and running the code + +To build and run the code, one can use the following commands: + +```{code-block} text +❯ fpm run +Project is up to date +Iterations: 10000, PI: 3.141391477611324 +Took: 0.092s, with absolute error: 2.0E-04 +``` + +And increasing the number of iterations for the approximation while +simultaneously enabling compiler optimizations with `--profile-release` + +```{code-block} text +❯ fpm run --profile-release -- 1000000000 +main.f90 done. +compute-pi-openmp done. +[100%] Project compiled successfully. +Iterations: 1000000000, PI: 3.141592651589789 +Took: 3.511s, with absolute error: 2.0E-09 +``` diff --git a/pages/how-to/index.md b/pages/how-to/index.md index c0f864a5a..79dc74916 100644 --- a/pages/how-to/index.md +++ b/pages/how-to/index.md @@ -2,6 +2,8 @@ # How-To guides -:::{note} This section contains practical guides and recipes for solving specific problems with fpm. + +:::{toctree} +compute-pi-openmp ::: diff --git a/src/how-to/compute-pi-openmp/app/main.f90 b/src/how-to/compute-pi-openmp/app/main.f90 new file mode 100644 index 000000000..90d8cbb13 --- /dev/null +++ b/src/how-to/compute-pi-openmp/app/main.f90 @@ -0,0 +1,41 @@ +program compute_pi_openmp + use, intrinsic :: iso_fortran_env, only: dp => real64, i8 => int64, real128 + implicit none + integer(kind=i8) :: i, n_iterations + real(kind=dp) :: delta, x, pi + real(kind=dp) :: start, end + + pi = 0.0_dp + n_iterations = get_iterations(10000_i8) + delta = 1.0_dp / n_iterations + x = 0.0_dp + + call cpu_time(start) + !$omp parallel do default(none) private(x) shared(delta, n_iterations) reduction(+:pi) + do i = 1, n_iterations + x = i * delta + pi = pi + sqrt(1.0_dp - x**2) + end do + !$omp end parallel do + call cpu_time(end) + + pi = 4.0_dp * pi / n_iterations + print "(A, I16, A, F25.15)", "Iterations: ", n_iterations, ", PI: ", pi + print "(A, F8.3, A, ES8.1)", "Took: ", end - start, "s, with absolute error: ", acos(-1.0_real128) - pi + +contains + + integer(i8) function get_iterations(default_iterations) + integer(kind=i8), intent(in) :: default_iterations + character(len=100) :: buffer, msg + integer :: stat + + get_iterations = default_iterations + if (command_argument_count() >= 1) then + call get_command_argument(1, buffer) + read (buffer, fmt=*, iostat=stat, iomsg=msg) get_iterations + if (stat /= 0) stop msg + end if + end function get_iterations + +end program compute_pi_openmp diff --git a/src/how-to/compute-pi-openmp/fpm.toml b/src/how-to/compute-pi-openmp/fpm.toml new file mode 100644 index 000000000..7244c2558 --- /dev/null +++ b/src/how-to/compute-pi-openmp/fpm.toml @@ -0,0 +1,8 @@ +name = "compute-pi-openmp" +version = "0.1.0" + +[dependencies] +openmp = "*" + +[[executable]] +name = "compute-pi-openmp"