module regr1_conserv_m ! Author: Lionel GUEZ use assert_eq_m, only: assert_eq use assert_m, only: assert use interpolation, only: locate implicit none interface regr1_conserv ! This generic procedure regrids a piecewise linear function (not ! necessarily continuous) by averaging it. This is a conservative ! regridding. The regridding operation is done on the first ! dimension of the input array. Input are positions of cell ! edges. The target grid should be included in the source grid: ! no extrapolation is allowed. ! The only difference between the procedures is the rank of the ! first argument. ! real, intent(in), rank >= 1:: vs ! (ns, ...) ! averages of cells of the source grid ! vs(is, ...) for [xs(is), xs(is + 1)] ! real, intent(in):: xs(:) ! (ns + 1) ! edges of cells of the source grid, in strictly ascending order ! real, intent(in):: xt(:) ! (nt + 1) ! edges of cells of the target grid, in strictly ascending order ! real, intent(in), optional, rank >= 1:: slope ! (ns, ...) ! same rank as vs ! slopes inside cells of the source grid ! slope(is, ...) for [xs(is), xs(is + 1)] ! If not present, slopes are taken equal to 0. The regridding is ! then first order. ! real, intent(out), rank >= 1:: vt(nt, ...) ! has the same rank as vs and slope ! averages of cells of the target grid ! vt(it, ...) for [xt(it), xt(it + 1)] ! ns and nt must be >= 1. ! See notes for explanations on the algorithm and justification ! of algorithmic choices. module procedure regr11_conserv, regr12_conserv, regr13_conserv, & regr14_conserv end interface regr1_conserv private public regr1_conserv contains subroutine regr11_conserv(vs, xs, xt, vt, slope) ! vs and slope have rank 1. real, intent(in):: vs(:) real, intent(in):: xs(:) real, intent(in):: xt(:) real, intent(out):: vt(:) real, intent(in), optional:: slope(:) ! Local: integer is, it, ns, nt logical slope_present !--------------------------------------------- ns = assert_eq(size(vs), size(xs) - 1, "regr11_conserv ns") nt = assert_eq(size(xt) - 1, size(vt), "regr11_conserv nt") ! Quick check on sort order: call assert(xs(1) < xs(2), "regr11_conserv xs bad order") call assert(xt(1) < xt(2), "regr11_conserv xt bad order") call assert(xs(1) <= xt(1) .and. xt(nt + 1) <= xs(ns + 1), & "regr11_conserv extrapolation") slope_present = present(slope) is = locate(xs, xt(1)) ! 1 <= is <= ns, because we forbid extrapolation do it = 1, nt ! 1 <= is <= ns ! xs(is) <= xt(it) < xs(is + 1) if (xt(it + 1) <= xs(is + 1)) then vt(it) = mean_lin(xt(it), xt(it + 1)) else vt(it) = mean_lin(xt(it), xs(is + 1)) * (xs(is + 1) - xt(it)) is = is + 1 do while (xs(is + 1) < xt(it + 1)) ! 1 <= is <= ns - 1 vt(it) = vt(it) + (xs(is + 1) - xs(is)) * vs(is) is = is + 1 end do ! 1 <= is <= ns vt(it) = (vt(it) + mean_lin(xs(is), xt(it + 1)) * (xt(it + 1) & - xs(is))) / (xt(it + 1) - xt(it)) end if if (xs(is + 1) == xt(it + 1)) is = is + 1 ! 1 <= is <= ns .or. it == nt end do contains real function mean_lin(a, b) ! mean in [a, b] of the linear function in [xs(is), xs(is + 1)] real, intent(in):: a, b !--------------------------------------------- if (slope_present) then mean_lin = slope(is) / 2. * (a + b - xs(is) - xs(is + 1)) + vs(is) else mean_lin = vs(is) end if end function mean_lin end subroutine regr11_conserv !******************************************** subroutine regr12_conserv(vs, xs, xt, vt, slope) ! vs and slope have rank 2. real, intent(in):: vs(:, :) real, intent(in):: xs(:) real, intent(in):: xt(:) real, intent(out):: vt(:, :) real, intent(in), optional:: slope(:, :) ! Local: integer is, it, ns, nt, n2 logical slope_present !--------------------------------------------- ns = assert_eq(size(vs, 1), size(xs) - 1, "regr12_conserv ns") nt = assert_eq(size(xt) - 1, size(vt, 1), "regr12_conserv nt") n2 = assert_eq(size(vs, 2), size(vt, 2), "regr12_conserv n2") ! Quick check on sort order: call assert(xs(1) < xs(2), "regr12_conserv xs bad order") call assert(xt(1) < xt(2), "regr12_conserv xt bad order") call assert(xs(1) <= xt(1) .and. xt(nt + 1) <= xs(ns + 1), & "regr12_conserv extrapolation") slope_present = present(slope) is = locate(xs, xt(1)) ! 1 <= is <= ns, because we forbid extrapolation do it = 1, nt ! 1 <= is <= ns ! xs(is) <= xt(it) < xs(is + 1) if (xt(it + 1) <= xs(is + 1)) then vt(it, :) = mean_lin(xt(it), xt(it + 1)) else vt(it, :) = mean_lin(xt(it), xs(is + 1)) * (xs(is + 1) - xt(it)) is = is + 1 do while (xs(is + 1) < xt(it + 1)) ! 1 <= is <= ns - 1 vt(it, :) = vt(it, :) + (xs(is + 1) - xs(is)) * vs(is, :) is = is + 1 end do ! 1 <= is <= ns vt(it, :) = (vt(it, :) + mean_lin(xs(is), xt(it + 1)) * (xt(it + 1) & - xs(is))) / (xt(it + 1) - xt(it)) end if if (xs(is + 1) == xt(it + 1)) is = is + 1 ! 1 <= is <= ns .or. it == nt end do contains function mean_lin(a, b) ! mean in [a, b] of the linear function in [xs(is), xs(is + 1)] real, intent(in):: a, b real mean_lin(n2) !--------------------------------------------- if (slope_present) then mean_lin = slope(is, :) / 2. * (a + b - xs(is) - xs(is + 1)) & + vs(is, :) else mean_lin = vs(is, :) end if end function mean_lin end subroutine regr12_conserv !******************************************** subroutine regr13_conserv(vs, xs, xt, vt, slope) ! vs and slope have rank 3. real, intent(in):: vs(:, :, :) real, intent(in):: xs(:) real, intent(in):: xt(:) real, intent(out):: vt(:, :, :) real, intent(in), optional:: slope(:, :, :) ! Local: integer is, it, ns, nt, n2, n3 logical slope_present !--------------------------------------------- ns = assert_eq(size(vs, 1), size(xs) - 1, "regr13_conserv ns") nt = assert_eq(size(xt) - 1, size(vt, 1), "regr13_conserv nt") n2 = assert_eq(size(vs, 2), size(vt, 2), "regr13_conserv n2") n3 = assert_eq(size(vs, 3), size(vt, 3), "regr13_conserv n3") ! Quick check on sort order: call assert(xs(1) < xs(2), "regr13_conserv xs bad order") call assert(xt(1) < xt(2), "regr13_conserv xt bad order") call assert(xs(1) <= xt(1) .and. xt(nt + 1) <= xs(ns + 1), & "regr13_conserv extrapolation") slope_present = present(slope) is = locate(xs, xt(1)) ! 1 <= is <= ns, because we forbid extrapolation do it = 1, nt ! 1 <= is <= ns ! xs(is) <= xt(it) < xs(is + 1) if (xt(it + 1) <= xs(is + 1)) then vt(it, :, :) = mean_lin(xt(it), xt(it + 1)) else vt(it, :, :) = mean_lin(xt(it), xs(is + 1)) * (xs(is + 1) - xt(it)) is = is + 1 do while (xs(is + 1) < xt(it + 1)) ! 1 <= is <= ns - 1 vt(it, :, :) = vt(it, :, :) + (xs(is + 1) - xs(is)) * vs(is, :, :) is = is + 1 end do ! 1 <= is <= ns vt(it, :, :) = (vt(it, :, :) + mean_lin(xs(is), xt(it + 1)) & * (xt(it + 1) - xs(is))) / (xt(it + 1) - xt(it)) end if if (xs(is + 1) == xt(it + 1)) is = is + 1 ! 1 <= is <= ns .or. it == nt end do contains function mean_lin(a, b) ! mean in [a, b] of the linear function in [xs(is), xs(is + 1)] real, intent(in):: a, b real mean_lin(n2, n3) !--------------------------------------------- if (slope_present) then mean_lin = slope(is, :, :) / 2. * (a + b - xs(is) - xs(is + 1)) & + vs(is, :, :) else mean_lin = vs(is, :, :) end if end function mean_lin end subroutine regr13_conserv !******************************************** subroutine regr14_conserv(vs, xs, xt, vt, slope) ! vs and slope have rank 4. real, intent(in):: vs(:, :, :, :) real, intent(in):: xs(:) real, intent(in):: xt(:) real, intent(out):: vt(:, :, :, :) real, intent(in), optional:: slope(:, :, :, :) ! Local: integer is, it, ns, nt, n2, n3, n4 logical slope_present !--------------------------------------------- ns = assert_eq(size(vs, 1), size(xs) - 1, "regr14_conserv ns") nt = assert_eq(size(xt) - 1, size(vt, 1), "regr14_conserv nt") n2 = assert_eq(size(vs, 2), size(vt, 2), "regr14_conserv n2") n3 = assert_eq(size(vs, 3), size(vt, 3), "regr14_conserv n3") n4 = assert_eq(size(vs, 4), size(vt, 4), "regr14_conserv n4") ! Quick check on sort order: call assert(xs(1) < xs(2), "regr14_conserv xs bad order") call assert(xt(1) < xt(2), "regr14_conserv xt bad order") call assert(xs(1) <= xt(1) .and. xt(nt + 1) <= xs(ns + 1), & "regr14_conserv extrapolation") slope_present = present(slope) is = locate(xs, xt(1)) ! 1 <= is <= ns, because we forbid extrapolation do it = 1, nt ! 1 <= is <= ns ! xs(is) <= xt(it) < xs(is + 1) if (xt(it + 1) <= xs(is + 1)) then vt(it, :, :, :) = mean_lin(xt(it), xt(it + 1)) else vt(it, :, :, :) = mean_lin(xt(it), xs(is + 1)) * (xs(is + 1) - xt(it)) is = is + 1 do while (xs(is + 1) < xt(it + 1)) ! 1 <= is <= ns - 1 vt(it, :, :, :) = vt(it, :, :, :) + (xs(is + 1) - xs(is)) & * vs(is, :, :, :) is = is + 1 end do ! 1 <= is <= ns vt(it, :, :, :) = (vt(it, :, :, :) + mean_lin(xs(is), xt(it + 1)) & * (xt(it + 1) - xs(is))) / (xt(it + 1) - xt(it)) end if if (xs(is + 1) == xt(it + 1)) is = is + 1 ! 1 <= is <= ns .or. it == nt end do contains function mean_lin(a, b) ! mean in [a, b] of the linear function in [xs(is), xs(is + 1)] real, intent(in):: a, b real mean_lin(n2, n3, n4) !--------------------------------------------- if (slope_present) then mean_lin = slope(is, :, :, :) / 2. * (a + b - xs(is) - xs(is + 1)) & + vs(is, :, :, :) else mean_lin = vs(is, :, :, :) end if end function mean_lin end subroutine regr14_conserv end module regr1_conserv_m