MODULE quadratures IMPLICIT none integer(kind=8) :: subintervals = 100 INTERFACE FUNCTION integrate(ibeg, iend, myfun, p) result(val) IMPLICIT none ! beginning of integration interval real(kind=8), intent(in) :: ibeg ! ending of integration interval real(kind=8), intent(in) :: iend ! function to be integrated procedure(funint) :: myfun ! polynomial order integer(kind=4), intent(in) :: p ! result of integration real(kind=8) :: val END FUNCTION integrate END INTERFACE INTERFACE FUNCTION quadrature(qbeg, qend, fun) result(val) IMPLICIT none real(kind=8), intent(in) :: qbeg, qend procedure(funint) :: fun real(kind=8) :: val END FUNCTION quadrature END INTERFACE INTERFACE FUNCTION funint(x) result(y) IMPLICIT none real(kind=8), intent(in) :: x real(kind=8) :: y END FUNCTION funint END INTERFACE CONTAINS FUNCTION integrate_generic(ibeg, iend, fun, quad) result(val) IMPLICIT none real(kind=8), intent(in) :: ibeg real(kind=8), intent(in) :: iend procedure(funint) :: fun procedure(quadrature) :: quad real(kind=8) :: val, subinterval_width, qbeg, qend real(kind=8), allocatable :: partval[:] integer(kind=8) :: min_i, max_i, i, subintervals_per_thread integer(kind=4) :: im allocate(partval[*]) subintervals_per_thread = & (subintervals + num_images() - 1) / num_images() min_i = subintervals_per_thread * (this_image() - 1) + 1 max_i = min(subintervals, subintervals_per_thread * this_image()) subinterval_width = (iend - ibeg) / subintervals ! compute integral using quadrature pointed by quad partval = 0 DO i = min_i, max_i qend = ibeg + i * subinterval_width qbeg = ibeg + (i - 1) * subinterval_width partval = partval + quad(qbeg, qend, fun) END DO IF (this_image() == 1 .and. num_images() > 1) THEN sync images([(im, im = 2, num_images())]) partval = partval + sum([(partval[im], im = 2, num_images())]) sync images([(im, im = 2, num_images())]) END IF IF (this_image() /= 1) THEN sync images(1) sync images(1) END IF val = partval[1] END FUNCTION integrate_generic FUNCTION newton_cotes(ibeg, iend, fun, p) result(val) IMPLICIT none real(kind=8), intent(in) :: ibeg real(kind=8), intent(in) :: iend procedure(funint) :: fun integer(kind=4), intent(in) :: p real(kind=8) :: val procedure(quadrature), pointer :: quad SELECT CASE (p) CASE (:-1) STOP "negative interpolationg polynomial order passed" CASE (0) quad => rectangle CASE (1) quad => trapeze CASE (2) quad => simpson_1_third CASE default STOP "Newton-Cotes quadratures only implemented for order < 3" END SELECT val = integrate_generic(ibeg, iend, fun, quad) END FUNCTION newton_cotes FUNCTION rectangle(qbeg, qend, fun) result(val) IMPLICIT none real(kind=8), intent(in) :: qbeg, qend procedure(funint) :: fun real(kind=8) :: val val = (qend - qbeg) * fun((qend + qbeg) * 0.5) END FUNCTION rectangle FUNCTION trapeze(qbeg, qend, fun) result(val) IMPLICIT none real(kind=8), intent(in) :: qbeg, qend procedure(funint) :: fun real(kind=8) :: val val = (qend - qbeg) * 0.5 * (fun(qbeg) + fun(qend)) END FUNCTION trapeze FUNCTION simpson_1_third(qbeg, qend, fun) result(val) IMPLICIT none real(kind=8), intent(in) :: qbeg, qend procedure(funint) :: fun real(kind=8) :: val val = (qend - qbeg) * (1/6.0) * & (fun(qbeg) + 4 * fun ((qbeg + qend) * 0.5) + fun(qend)) END FUNCTION simpson_1_third FUNCTION gauss(ibeg, iend, fun, p) result(val) IMPLICIT none real(kind=8), intent(in) :: ibeg real(kind=8), intent(in) :: iend procedure(funint) :: fun integer(kind=4), intent(in) :: p real(kind=8) :: val procedure(quadrature), pointer :: quad SELECT CASE (p) CASE (:0) STOP "non-positive Legendre polynomial order passed" CASE (1) quad => gauss_n1 CASE (2) quad => gauss_n2 CASE (3) quad => gauss_n3 CASE default STOP "Gauss quadratures only implemented with roots of" & // " Legendgre polynomial of order <= 3" END SELECT val = integrate_generic(ibeg, iend, fun, quad) END FUNCTION gauss FUNCTION gauss_generic(mid, halfwidth, fun, points, weights) & result(val) IMPLICIT none real(kind=8), intent(in) :: mid, halfwidth, points(:), weights(:) procedure(funint) :: fun real(kind=8) :: val integer(kind=4) :: i val = halfwidth * sum(weights * & [(fun(points(i) * halfwidth + mid), i = 1, size(points))]) END FUNCTION gauss_generic FUNCTION gauss_n1(qbeg, qend, fun) result(val) IMPLICIT none real(kind=8), intent(in) :: qbeg, qend procedure(funint) :: fun real(kind=8) :: val, weights(1) = [2], points(1) = [0] val = gauss_generic((qbeg + qend) * 0.5, (qend - qbeg) * 0.5, & fun, points, weights) END FUNCTION gauss_n1 FUNCTION gauss_n2(qbeg, qend, fun) result(val) IMPLICIT none real(kind=8), intent(in) :: qbeg, qend procedure(funint) :: fun real(kind=8) :: val, weights(2) = [1, 1], & points(2) = [1 / sqrt(3.0), -1 / sqrt(3.0)] val = gauss_generic((qbeg + qend) * 0.5, (qend - qbeg) * 0.5, & fun, points, weights) END FUNCTION gauss_n2 FUNCTION gauss_n3(qbeg, qend, fun) result(val) IMPLICIT none real(kind=8), intent(in) :: qbeg, qend procedure(funint) :: fun real(kind=8) :: val, weights(3) = [8 / 9.0, 5 / 9.0, 5 / 9.0],& points(3) = [0.0, sqrt(3 / 5.0), -sqrt(3 / 5.0)] val = gauss_generic((qbeg + qend) * 0.5, (qend - qbeg) * 0.5, & fun, points, weights) END FUNCTION gauss_n3 END MODULE quadratures