submodule (stdlib_stats) stdlib_stats_moment_mask

  use, intrinsic:: ieee_arithmetic, only: ieee_value, ieee_quiet_nan
  use stdlib_error, only: error_stop
  use stdlib_optval, only: optval
  implicit none

contains

      module function moment_mask_1_rsp_rsp(x, order, dim, center, mask) result(res)
        real(sp), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(sp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        real(sp) :: res

        integer :: i
        real(sp) :: n
        real(sp), allocatable :: mean_

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i) -&
                  center)**order,&
                    0._sp,&
                    mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i) - mean_)**order,&
                    0._sp,&
                    mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_rsp_rsp
      module function moment_mask_2_rsp_rsp(x, order, dim, center, mask) result(res)
        real(sp), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(sp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        real(sp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(sp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        real(sp), allocatable :: mean_(:)

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) -&
                  center)**order,&
                    0._sp,&
                    mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) - mean_)**order,&
                    0._sp,&
                    mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) -&
                  center)**order,&
                    0._sp,&
                    mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) - mean_)**order,&
                    0._sp,&
                    mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_rsp_rsp
      module function moment_mask_3_rsp_rsp(x, order, dim, center, mask) result(res)
        real(sp), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(sp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        real(sp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(sp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        real(sp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) -&
                  center)**order,&
                    0._sp,&
                    mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) - mean_)**order,&
                    0._sp,&
                    mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) -&
                  center)**order,&
                    0._sp,&
                    mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) - mean_)**order,&
                    0._sp,&
                    mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) -&
                  center)**order,&
                    0._sp,&
                    mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) - mean_)**order,&
                    0._sp,&
                    mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_rsp_rsp
      module function moment_mask_4_rsp_rsp(x, order, dim, center, mask) result(res)
        real(sp), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(sp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        real(sp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(sp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        real(sp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) -&
                  center)**order,&
                    0._sp,&
                    mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) - mean_)**order,&
                    0._sp,&
                    mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) -&
                  center)**order,&
                    0._sp,&
                    mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) - mean_)**order,&
                    0._sp,&
                    mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) -&
                  center)**order,&
                    0._sp,&
                    mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) - mean_)**order,&
                    0._sp,&
                    mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) -&
                  center)**order,&
                    0._sp,&
                    mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) - mean_)**order,&
                    0._sp,&
                    mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_rsp_rsp
      module function moment_mask_1_rdp_rdp(x, order, dim, center, mask) result(res)
        real(dp), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        real(dp) :: res

        integer :: i
        real(dp) :: n
        real(dp), allocatable :: mean_

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i) -&
                  center)**order,&
                    0._dp,&
                    mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i) - mean_)**order,&
                    0._dp,&
                    mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_rdp_rdp
      module function moment_mask_2_rdp_rdp(x, order, dim, center, mask) result(res)
        real(dp), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        real(dp), allocatable :: mean_(:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) -&
                  center)**order,&
                    0._dp,&
                    mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) - mean_)**order,&
                    0._dp,&
                    mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) -&
                  center)**order,&
                    0._dp,&
                    mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) - mean_)**order,&
                    0._dp,&
                    mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_rdp_rdp
      module function moment_mask_3_rdp_rdp(x, order, dim, center, mask) result(res)
        real(dp), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        real(dp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) -&
                  center)**order,&
                    0._dp,&
                    mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) - mean_)**order,&
                    0._dp,&
                    mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) -&
                  center)**order,&
                    0._dp,&
                    mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) - mean_)**order,&
                    0._dp,&
                    mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) -&
                  center)**order,&
                    0._dp,&
                    mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) - mean_)**order,&
                    0._dp,&
                    mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_rdp_rdp
      module function moment_mask_4_rdp_rdp(x, order, dim, center, mask) result(res)
        real(dp), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        real(dp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) -&
                  center)**order,&
                    0._dp,&
                    mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) - mean_)**order,&
                    0._dp,&
                    mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) -&
                  center)**order,&
                    0._dp,&
                    mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) - mean_)**order,&
                    0._dp,&
                    mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) -&
                  center)**order,&
                    0._dp,&
                    mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) - mean_)**order,&
                    0._dp,&
                    mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) -&
                  center)**order,&
                    0._dp,&
                    mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) - mean_)**order,&
                    0._dp,&
                    mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_rdp_rdp
      module function moment_mask_1_rqp_rqp(x, order, dim, center, mask) result(res)
        real(qp), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(qp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        real(qp) :: res

        integer :: i
        real(qp) :: n
        real(qp), allocatable :: mean_

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i) -&
                  center)**order,&
                    0._qp,&
                    mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i) - mean_)**order,&
                    0._qp,&
                    mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_rqp_rqp
      module function moment_mask_2_rqp_rqp(x, order, dim, center, mask) result(res)
        real(qp), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(qp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        real(qp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(qp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        real(qp), allocatable :: mean_(:)

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) -&
                  center)**order,&
                    0._qp,&
                    mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) - mean_)**order,&
                    0._qp,&
                    mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) -&
                  center)**order,&
                    0._qp,&
                    mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) - mean_)**order,&
                    0._qp,&
                    mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_rqp_rqp
      module function moment_mask_3_rqp_rqp(x, order, dim, center, mask) result(res)
        real(qp), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(qp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        real(qp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(qp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        real(qp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) -&
                  center)**order,&
                    0._qp,&
                    mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) - mean_)**order,&
                    0._qp,&
                    mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) -&
                  center)**order,&
                    0._qp,&
                    mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) - mean_)**order,&
                    0._qp,&
                    mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) -&
                  center)**order,&
                    0._qp,&
                    mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) - mean_)**order,&
                    0._qp,&
                    mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_rqp_rqp
      module function moment_mask_4_rqp_rqp(x, order, dim, center, mask) result(res)
        real(qp), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(qp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        real(qp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(qp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        real(qp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) -&
                  center)**order,&
                    0._qp,&
                    mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) - mean_)**order,&
                    0._qp,&
                    mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) -&
                  center)**order,&
                    0._qp,&
                    mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) - mean_)**order,&
                    0._qp,&
                    mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) -&
                  center)**order,&
                    0._qp,&
                    mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) - mean_)**order,&
                    0._qp,&
                    mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) -&
                  center)**order,&
                    0._qp,&
                    mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) - mean_)**order,&
                    0._qp,&
                    mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_rqp_rqp
      module function moment_mask_1_csp_csp(x, order, dim, center, mask) result(res)
        complex(sp), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(sp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        complex(sp) :: res

        integer :: i
        real(sp) :: n
        complex(sp), allocatable :: mean_

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_csp_csp
      module function moment_mask_2_csp_csp(x, order, dim, center, mask) result(res)
        complex(sp), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(sp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        complex(sp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(sp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        complex(sp), allocatable :: mean_(:)

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_csp_csp
      module function moment_mask_3_csp_csp(x, order, dim, center, mask) result(res)
        complex(sp), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(sp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        complex(sp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(sp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        complex(sp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_csp_csp
      module function moment_mask_4_csp_csp(x, order, dim, center, mask) result(res)
        complex(sp), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(sp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        complex(sp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(sp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        complex(sp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), sp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) -&
                  center)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) - mean_)**order,&
                    cmplx(0,0,kind=sp),&
                    mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_csp_csp
      module function moment_mask_1_cdp_cdp(x, order, dim, center, mask) result(res)
        complex(dp), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(dp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        complex(dp) :: res

        integer :: i
        real(dp) :: n
        complex(dp), allocatable :: mean_

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_cdp_cdp
      module function moment_mask_2_cdp_cdp(x, order, dim, center, mask) result(res)
        complex(dp), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        complex(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        complex(dp), allocatable :: mean_(:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_cdp_cdp
      module function moment_mask_3_cdp_cdp(x, order, dim, center, mask) result(res)
        complex(dp), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        complex(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        complex(dp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_cdp_cdp
      module function moment_mask_4_cdp_cdp(x, order, dim, center, mask) result(res)
        complex(dp), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        complex(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        complex(dp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) -&
                  center)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) - mean_)**order,&
                    cmplx(0,0,kind=dp),&
                    mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_cdp_cdp
      module function moment_mask_1_cqp_cqp(x, order, dim, center, mask) result(res)
        complex(qp), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(qp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        complex(qp) :: res

        integer :: i
        real(qp) :: n
        complex(qp), allocatable :: mean_

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_cqp_cqp
      module function moment_mask_2_cqp_cqp(x, order, dim, center, mask) result(res)
        complex(qp), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(qp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        complex(qp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(qp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        complex(qp), allocatable :: mean_(:)

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_cqp_cqp
      module function moment_mask_3_cqp_cqp(x, order, dim, center, mask) result(res)
        complex(qp), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(qp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        complex(qp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(qp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        complex(qp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_cqp_cqp
      module function moment_mask_4_cqp_cqp(x, order, dim, center, mask) result(res)
        complex(qp), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        complex(qp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        complex(qp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(qp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        complex(qp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), qp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge( (x(i, :, :, :) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge( (x(:, i, :, :) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge( (x(:, :, i, :) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) -&
                  center)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge( (x(:, :, :, i) - mean_)**order,&
                    cmplx(0,0,kind=qp),&
                    mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_cqp_cqp

      module function moment_mask_1_iint8_dp(x, order, dim, center, mask) result(res)
        integer(int8), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        real(dp) :: res

        integer :: i
        real(dp) :: n
        real(dp), allocatable :: mean_

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) -&
                                    center)**order,&
                                    0._dp, mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_iint8_dp
      module function moment_mask_2_iint8_dp(x, order, dim, center, mask) result(res)
        integer(int8), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        real(dp), allocatable :: mean_(:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_iint8_dp
      module function moment_mask_3_iint8_dp(x, order, dim, center, mask) result(res)
        integer(int8), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        real(dp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_iint8_dp
      module function moment_mask_4_iint8_dp(x, order, dim, center, mask) result(res)
        integer(int8), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        real(dp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_iint8_dp
      module function moment_mask_1_iint16_dp(x, order, dim, center, mask) result(res)
        integer(int16), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        real(dp) :: res

        integer :: i
        real(dp) :: n
        real(dp), allocatable :: mean_

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) -&
                                    center)**order,&
                                    0._dp, mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_iint16_dp
      module function moment_mask_2_iint16_dp(x, order, dim, center, mask) result(res)
        integer(int16), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        real(dp), allocatable :: mean_(:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_iint16_dp
      module function moment_mask_3_iint16_dp(x, order, dim, center, mask) result(res)
        integer(int16), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        real(dp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_iint16_dp
      module function moment_mask_4_iint16_dp(x, order, dim, center, mask) result(res)
        integer(int16), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        real(dp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_iint16_dp
      module function moment_mask_1_iint32_dp(x, order, dim, center, mask) result(res)
        integer(int32), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        real(dp) :: res

        integer :: i
        real(dp) :: n
        real(dp), allocatable :: mean_

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) -&
                                    center)**order,&
                                    0._dp, mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_iint32_dp
      module function moment_mask_2_iint32_dp(x, order, dim, center, mask) result(res)
        integer(int32), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        real(dp), allocatable :: mean_(:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_iint32_dp
      module function moment_mask_3_iint32_dp(x, order, dim, center, mask) result(res)
        integer(int32), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        real(dp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_iint32_dp
      module function moment_mask_4_iint32_dp(x, order, dim, center, mask) result(res)
        integer(int32), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        real(dp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_iint32_dp
      module function moment_mask_1_iint64_dp(x, order, dim, center, mask) result(res)
        integer(int64), intent(in) :: x(:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center
        logical, intent(in) :: mask(:)
        real(dp) :: res

        integer :: i
        real(dp) :: n
        real(dp), allocatable :: mean_

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) -&
                                    center)**order,&
                                    0._dp, mask(i))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_1_iint64_dp
      module function moment_mask_2_iint64_dp(x, order, dim, center, mask) result(res)
        integer(int64), intent(in) :: x(:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim))
        logical, intent(in) :: mask(:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim))
        real(dp), allocatable :: mean_(:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_2_iint64_dp
      module function moment_mask_3_iint64_dp(x, order, dim, center, mask) result(res)
        integer(int64), intent(in) :: x(:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim))
        logical, intent(in) :: mask(:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim))
        real(dp), allocatable :: mean_(:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_3_iint64_dp
      module function moment_mask_4_iint64_dp(x, order, dim, center, mask) result(res)
        integer(int64), intent(in) :: x(:,:,:,:)
        integer, intent(in) :: order
        integer, intent(in) :: dim
        real(dp), intent(in), optional :: center(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3),&
            & mask=2<dim), merge(size(x, 3), size(x, 4), mask=3<dim))
        logical, intent(in) :: mask(:,:,:,:)
        real(dp) :: res(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))

        integer :: i
        real(dp) :: n(merge(size(x, 1), size(x, 2), mask=1<dim), merge(size(x, 2), size(x, 3), mask=2<dim), merge(size(x, 3),&
            & size(x, 4), mask=3<dim))
        real(dp), allocatable :: mean_(:,:,:)

        n = real(count(mask, dim), dp)

        res = 0
        select case(dim)
          case(1)
            if (present(center)) then
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(i, :, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 1, mask))
              do i = 1, size(x, 1)
                res = res + merge((real(x(i, :, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(i, :, :, :))
              end do
              deallocate(mean_)
            end if
          case(2)
            if (present(center)) then
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, i, :, :))
              end do
            else
              allocate(mean_, source = mean(x, 2, mask))
              do i = 1, size(x, 2)
                res = res + merge((real(x(:, i, :, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, i, :, :))
              end do
              deallocate(mean_)
            end if
          case(3)
            if (present(center)) then
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, i, :))
              end do
            else
              allocate(mean_, source = mean(x, 3, mask))
              do i = 1, size(x, 3)
                res = res + merge((real(x(:, :, i, :), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, i, :))
              end do
              deallocate(mean_)
            end if
          case(4)
            if (present(center)) then
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) -&
                                    center)**order,&
                                    0._dp, mask(:, :, :, i))
              end do
            else
              allocate(mean_, source = mean(x, 4, mask))
              do i = 1, size(x, 4)
                res = res + merge((real(x(:, :, :, i), dp) - mean_)&
                                    **order,&
                                    0._dp, mask(:, :, :, i))
              end do
              deallocate(mean_)
            end if
          case default
            call error_stop("ERROR (moment): wrong dimension")
        end select
        res = res / n

      end function moment_mask_4_iint64_dp

end submodule


! chk_bit_functions.f90 --
!     Check if the new Fortran 2008 bit functions are all implemented
!
program chk_bit_functions
    implicit none

    integer               :: i, j, k
    integer, dimension(3) :: array

    write( *, '(a)' ) 'This program simply calls the various Fortran 2008 bit functions:'
    write( *, '(a)' ) '(No attempt is made to check the results)'

    i = 1234
    j = 4321

    write( *, '(a)'     )     'Combined shifting:'
    write( *, '(a,i12)' )     '    dshiftl:   ', dshiftl(i,j,2)
    write( *, '(a,i12)' )     '    dshiftr:   ', dshiftr(i,j,2)

    write( *, '(a)'     )     'Counting bits:'
    write( *, '(a,i12)' )     '    leadz:     ', leadz(i)
    write( *, '(a,i12)' )     '    popcnt:    ', popcnt(i)
    write( *, '(a,i12)' )     '    poppar:    ', poppar(i)
    write( *, '(a,i12)' )     '    trailz:    ', trailz(i)

    write( *, '(a)'         ) 'Masking bits:'
    k = 3
    write( *, '(a,i12,b33)' ) '    maskl:     ', maskl(k), maskl(k)
    write( *, '(a,i12,b33)' ) '    maskr:     ', maskr(k), maskr(k)

    write( *, '(a)'         ) 'Shifting bits:'
    write( *, '(a,i12,b33)' ) '    shifta:    ', shifta(i,k), shifta(i,k)
    write( *, '(a,i12,b33)' ) '    shiftl:    ', shiftl(i,k), shiftl(i,k)
    write( *, '(a,i12,b33)' ) '    shiftr:    ', shiftr(i,k), shiftr(i,k)

    write( *, '(a)'         ) 'Merging bits:'
    k = 31
    write( *, '(a,i12,b33)' ) '    merge_bits:', merge_bits(i,j,k), merge_bits(i,j,k)

    write( *, '(a)'         ) 'Bit transformational functions:'
    array = [1,2,3]
    write( *, '(a,i12,b33)' ) '    iall:      ', iall(array), iall(array)
    write( *, '(a,i12,b33)' ) '    iany:      ', iany(array), iany(array)
    write( *, '(a,i12,b33)' ) '    iparity:   ', iparity(array), iparity(array)

end program chk_bit_functions


*DECK CSROT
      SUBROUTINE CSROT (N, CX, INCX, CY, INCY, C, S)
C***BEGIN PROLOGUE  CSROT
C***PURPOSE  Apply a plane Givens rotation.
C***LIBRARY   SLATEC (BLAS)
C***CATEGORY  D1B10
C***TYPE      COMPLEX (SROT-S, DROT-D, CSROT-C)
C***KEYWORDS  BLAS, GIVENS ROTATION, GIVENS TRANSFORMATION,
C             LINEAR ALGEBRA, PLANE ROTATION, VECTOR
C***AUTHOR  Dongarra, J., (ANL)
C***DESCRIPTION
C
C     CSROT applies the complex Givens rotation
C
C          (X)   ( C S)(X)
C          (Y) = (-S C)(Y)
C
C     N times where for I = 0,...,N-1
C
C          X = CX(LX+I*INCX)
C          Y = CY(LY+I*INCY),
C
C     where LX = 1 if INCX .GE. 0, else LX = 1+(1-N)*INCX, and LY is
C     defined in a similar way using INCY.
C
C     Argument Description
C
C        N      (integer)  number of elements in each vector
C
C        CX     (complex array)  beginning of one vector
C
C        INCX   (integer)  memory spacing of successive elements
C               of vector CX
C
C        CY     (complex array)  beginning of the other vector
C
C        INCY   (integer)  memory spacing of successive elements
C               of vector CY
C
C        C      (real)  cosine term of the rotation
C
C        S      (real)  sine term of the rotation.
C
C***REFERENCES  J. J. Dongarra, J. R. Bunch, C. B. Moler, and G. W.
C                 Stewart, LINPACK Users' Guide, SIAM, 1979.
C***ROUTINES CALLED  (NONE)
C***REVISION HISTORY  (YYMMDD)
C   810223  DATE WRITTEN
C   890831  Modified array declarations.  (WRB)
C   890831  REVISION DATE from Version 3.2
C   891214  Prologue converted to Version 4.0 format.  (BAB)
C   920310  Corrected definition of LX in DESCRIPTION.  (WRB)
C   920501  Reformatted the REFERENCES section.  (WRB)
C***END PROLOGUE  CSROT
      COMPLEX CX(*), CY(*), CTEMP
      REAL C, S
      INTEGER I, INCX, INCY, IX, IY, N
C***FIRST EXECUTABLE STATEMENT  CSROT
      IF (N .LE. 0) RETURN
      IF (INCX.EQ.1 .AND. INCY.EQ.1)GO TO 20
C
C     Code for unequal increments or equal increments not equal to 1.
C
      IX = 1
      IY = 1
      IF (INCX .LT. 0) IX = (-N+1)*INCX + 1
      IF (INCY .LT. 0) IY = (-N+1)*INCY + 1
      DO 10 I = 1,N
        CTEMP = C*CX(IX) + S*CY(IY)
        CY(IY) = C*CY(IY) - S*CX(IX)
        CX(IX) = CTEMP
        IX = IX + INCX
        IY = IY + INCY
   10 CONTINUE
      RETURN
C
C     Code for both increments equal to 1.
C
   20 DO 30 I = 1,N
        CTEMP = C*CX(I) + S*CY(I)
        CY(I) = C*CY(I) - S*CX(I)
        CX(I) = CTEMP
   30 CONTINUE
      RETURN
      END