  module ca_module

    use vtype_module

    implicit none

    private


    real(dp), parameter :: &
         minval0    = -1.0d20 , &
         maxval0    = -minval0, &
         fillvalue0 = -1.0d20


    public :: &
         ca_add, &
         ca_ave, &
         ca_zm , &
         ca_mul, &
         ca_div


    interface ca_add
       module procedure &
            ca_add_inout_real, ca_add_inout_2d_real, &
            ca_add_inout_dble, ca_add_inout_2d_dble, &
            ca_add_real, ca_add_2d_real, &
            ca_add_dble, ca_add_2d_dble
    end interface

    interface ca_ave
       module procedure &
            ca_ave_real, ca_ave_2d_real, &
            ca_ave_dble, ca_ave_2d_dble
    end interface

    interface ca_zm
       module procedure &
            ca_zm_real, ca_zm_2d_real, &
            ca_zm_dble, ca_zm_2d_dble
    end interface

    interface ca_mul
       module procedure &
            ca_mul_inout_real, ca_mul_inout_2d_real, &
            ca_mul_inout_dble, ca_mul_inout_2d_dble, &
            ca_mul_real, ca_mul_2d_real, &
            ca_mul_dble, ca_mul_2d_dble
    end interface

    interface ca_div
       module procedure &
            ca_div_real, ca_div_2d_real, &
            ca_div_dble, ca_div_2d_dble, &
            ca_div_inout_real, ca_div_inout_2d_real, &
            ca_div_inout_dble, ca_div_inout_2d_dble
    end interface


    !**************************************************************************

  contains

    !**************************************************************************

    subroutine ca_add_inout_real( im, jm, km, in_arr, inout_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm, km
      real(sp)    , intent(in   )           :: in_arr   ( im, jm, km )
      real(sp)    , intent(inout)           :: inout_arr( im, jm, km )
      real(sp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if

      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if(        ( in_arr   ( i, j, k ) .ge. minval ) &
                    .and. ( in_arr   ( i, j, k ) .le. maxval ) &
                    .and. ( inout_arr( i, j, k ) .ge. minval ) &
                    .and. ( inout_arr( i, j, k ) .le. maxval ) ) then
                  inout_arr( i, j, k ) &
                       = inout_arr( i, j, k ) + in_arr( i, j, k )
               else
                  inout_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_add_inout_real

    !**************************************************************************

    subroutine ca_add_inout_2d_real( im, jm, in_arr, inout_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm
      real(sp)    , intent(in   )           :: in_arr   ( im, jm )
      real(sp)    , intent(inout)           :: inout_arr( im, jm )
      real(sp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: in_arr3d   ( im, jm, 1 )
      real(sp)     :: inout_arr3d( im, jm, 1 )


      in_arr3d   ( :, :, 1 ) = in_arr   ( :, : )
      inout_arr3d( :, :, 1 ) = inout_arr( :, : )

      call ca_add( im, jm, 1, in_arr3d, inout_arr3d, &
           fillvalue, minset, maxset )

      inout_arr( :, : ) = inout_arr3d( :, :, 1 )


    end subroutine ca_add_inout_2d_real

    !**************************************************************************

    subroutine ca_add_inout_dble( im, jm, km, in_arr, inout_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm, km
      real(dp)    , intent(in   )           :: in_arr   ( im, jm, km )
      real(dp)    , intent(inout)           :: inout_arr( im, jm, km )
      real(dp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if

      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if(        ( in_arr   ( i, j, k ) .ge. minval ) &
                    .and. ( in_arr   ( i, j, k ) .le. maxval ) &
                    .and. ( inout_arr( i, j, k ) .ge. minval ) &
                    .and. ( inout_arr( i, j, k ) .le. maxval ) ) then
                  inout_arr( i, j, k ) = inout_arr( i, j, k ) + in_arr( i, j, k )
               else
                  inout_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_add_inout_dble

    !**************************************************************************

    subroutine ca_add_inout_2d_dble( im, jm, in_arr, inout_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm
      real(dp)    , intent(in   )           :: in_arr   ( im, jm )
      real(dp)    , intent(inout)           :: inout_arr( im, jm )
      real(dp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: in_arr3d   ( im, jm, 1 )
      real(dp)     :: inout_arr3d( im, jm, 1 )


      in_arr3d   ( :, :, 1 ) = in_arr   ( :, : )
      inout_arr3d( :, :, 1 ) = inout_arr( :, : )

      call ca_add( im, jm, 1, in_arr3d, inout_arr3d, &
           fillvalue, minset, maxset )

      inout_arr( :, : ) = inout_arr3d( :, :, 1 )


    end subroutine ca_add_inout_2d_dble

    !**************************************************************************

    subroutine ca_add_real( im, jm, km, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(sp)    , intent(in )           :: &
           in_arr1( im, jm, km ), in_arr2( im, jm, km )
      real(sp)    , intent(out)           :: out_arr( im, jm, km )
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if

      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr1( i, j, k ) .ge. minval ) &
                    .and. ( in_arr1( i, j, k ) .le. maxval ) &
                    .and. ( in_arr2( i, j, k ) .ge. minval ) &
                    .and. ( in_arr2( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr1( i, j, k ) + in_arr2( i, j, k )
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_add_real

    !**************************************************************************

    subroutine ca_add_2d_real( im, jm, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(sp)    , intent(in )           :: &
           in_arr1( im, jm ), in_arr2( im, jm )
      real(sp)    , intent(out)           :: out_arr( im, jm )
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: in_arr3d1( im, jm, 1 ), in_arr3d2( im, jm, 1 )
      real(sp)     :: out_arr3d( im, jm, 1 )


      in_arr3d1( :, :, 1 ) = in_arr1( :, : )
      in_arr3d2( :, :, 1 ) = in_arr2( :, : )

      call ca_add( im, jm, 1, in_arr3d1, in_arr3d2, out_arr3d, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_add_2d_real

    !**************************************************************************

    subroutine ca_add_dble( im, jm, km, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(dp)    , intent(in )           :: &
           in_arr1( im, jm, km ), in_arr2( im, jm, km )
      real(dp)    , intent(out)           :: out_arr( im, jm, km )
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if

      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr1( i, j, k ) .ge. minval ) &
                    .and. ( in_arr1( i, j, k ) .le. maxval ) &
                    .and. ( in_arr2( i, j, k ) .ge. minval ) &
                    .and. ( in_arr2( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr1( i, j, k ) + in_arr2( i, j, k )
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_add_dble

    !**************************************************************************

    subroutine ca_add_2d_dble( im, jm, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(dp)    , intent(in )           :: &
           in_arr1( im, jm ), in_arr2( im, jm )
      real(dp)    , intent(out)           :: out_arr( im, jm )
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: in_arr3d1( im, jm, 1 ), in_arr3d2( im, jm, 1 )
      real(dp)     :: out_arr3d( im, jm, 1 )


      in_arr3d1( :, :, 1 ) = in_arr1( :, : )
      in_arr3d2( :, :, 1 ) = in_arr2( :, : )

      call ca_add( im, jm, 1, in_arr3d1, in_arr3d2, out_arr3d, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_add_2d_dble

    !**************************************************************************

    subroutine ca_ave_real( im, jm, km, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset)


      integer(i4b), intent(in )           :: im, jm, km
      real(sp)    , intent(in )           :: &
           in_arr1( im, jm, km ), in_arr2( im, jm, km )
      real(sp)    , intent(out)           :: out_arr( im, jm, km )
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr1( i, j, k ) .ge. minval ) &
                    .and. ( in_arr1( i, j, k ) .le. maxval ) &
                    .and. ( in_arr2( i, j, k ) .ge. minval ) &
                    .and. ( in_arr2( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr1( i, j, k ) + in_arr2( i, j, k )
                  out_arr( i, j, k ) = out_arr( i, j, k ) / 2.0d0
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_ave_real

    !**************************************************************************

    subroutine ca_ave_2d_real( im, jm, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(sp)    , intent(in )           :: &
           in_arr1( im, jm ), in_arr2( im, jm )
      real(sp)    , intent(out)           :: out_arr( im, jm )
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: in_arr3d1( im, jm, 1 ), in_arr3d2( im, jm, 1 )
      real(sp)     :: out_arr3d( im, jm, 1 )


      in_arr3d1( :, :, 1 ) = in_arr1( :, : )
      in_arr3d2( :, :, 1 ) = in_arr2( :, : )

      call ca_ave( im, jm, 1, in_arr3d1, in_arr3d2, out_arr3d, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_ave_2d_real

    !**************************************************************************

    subroutine ca_ave_dble( im, jm, km, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(dp)    , intent(in )           :: &
           in_arr1( im, jm, km ), in_arr2( im, jm, km )
      real(dp)    , intent(out)           :: out_arr( im, jm, km )
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr1( i, j, k ) .ge. minval ) &
                    .and. ( in_arr1( i, j, k ) .le. maxval ) &
                    .and. ( in_arr2( i, j, k ) .ge. minval ) &
                    .and. ( in_arr2( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr1( i, j, k ) + in_arr2( i, j, k )
                  out_arr( i, j, k ) = out_arr( i, j, k ) / 2.0d0
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_ave_dble

    !**************************************************************************

    subroutine ca_ave_2d_dble( im, jm, in_arr1, in_arr2, out_arr, &
         fillvalue, minset, maxset )

      integer(i4b), intent(in )           :: im, jm
      real(dp)    , intent(in )           :: &
           in_arr1( im, jm ), in_arr2( im, jm )
      real(dp)    , intent(out)           :: out_arr( im, jm )
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset



      !
      ! Local variables
      !
      real(dp)     :: in_arr3d1( im, jm, 1 ), in_arr3d2( im, jm, 1 )
      real(dp)     :: out_arr3d( im, jm, 1 )


      in_arr3d1( :, :, 1 ) = in_arr1( :, : )
      in_arr3d2( :, :, 1 ) = in_arr2( :, : )

      call ca_ave( im, jm, 1, in_arr3d1, in_arr3d2, out_arr3d, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_ave_2d_dble

    !**************************************************************************

    subroutine ca_zm_real( im, jm, km, in_array, zm_array, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(sp)    , intent(in )           :: in_array( im, jm, km )
      real(sp)    , intent(out)           :: zm_array( jm, km )
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: dnum( jm, km )
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      zm_array( :, : ) = 0.0
      dnum    ( :, : ) = 0

      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_array( i, j, k ) .ge. minval ) &
                    .and. ( in_array( i, j, k ) .le. maxval ) ) then
                  zm_array( j, k ) = zm_array( j, k ) + in_array( i, j, k )
                  dnum    ( j, k ) = dnum    ( j, k ) + 1
               end if
            end do
         end do
      end do

      do k = 1, km
         do j = 1, jm
            if( dnum( j, k ) .eq. 0 ) then
               zm_array( j, k ) = fv
            else
               zm_array( j, k ) = zm_array( j, k ) / dnum( j, k )
            end if
         end do
      end do


    end subroutine ca_zm_real

    !**************************************************************************

    subroutine ca_zm_2d_real( im, jm, in_array, zm_array, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(sp)    , intent(in )           :: in_array( im, jm )
      real(sp)    , intent(out)           :: zm_array( jm )
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: in_array3d( im, jm, 1 )
      real(sp)     :: zm_array2d( jm, 1 )


      in_array3d( :, :, 1 ) = in_array( :, : )

      call ca_zm( im, jm, 1, in_array3d, zm_array2d, &
           fillvalue, minset, maxset )

      zm_array( : ) = zm_array2d( :, 1 )


    end subroutine ca_zm_2d_real

    !**************************************************************************

    subroutine ca_zm_dble( im, jm, km, in_array, zm_array, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(dp)    , intent(in )           :: in_array( im, jm, km )
      real(dp)    , intent(out)           :: zm_array( jm, km )
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: dnum( jm, km )
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if

      zm_array( :, : ) = 0.0
      dnum    ( :, : ) = 0

      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_array( i, j, k ) .ge. minval ) &
                    .and. ( in_array( i, j, k ) .le. maxval ) ) then
                  zm_array( j, k ) = zm_array( j, k ) + in_array( i, j, k )
                  dnum    ( j, k ) = dnum    ( j, k ) + 1
               end if
            end do
         end do
      end do

      do k = 1, km
         do j = 1, jm
            if( dnum( j, k ) .eq. 0 ) then
               zm_array( j, k ) = fv
            else
               zm_array( j, k ) = zm_array( j, k ) / dnum( j, k )
            end if
         end do
      end do


    end subroutine ca_zm_dble

    !**************************************************************************

    subroutine ca_zm_2d_dble( im, jm, in_array, zm_array, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(dp)    , intent(in )           :: in_array( im, jm )
      real(dp)    , intent(out)           :: zm_array( jm )
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: in_array3d( im, jm, 1 )
      real(dp)     :: zm_array2d( jm, 1 )


      in_array3d( :, :, 1 ) = in_array( :, : )

      call ca_zm( im, jm, 1, in_array3d, zm_array2d, &
           fillvalue, minset, maxset )

      zm_array( : ) = zm_array2d( :, 1 )


    end subroutine ca_zm_2d_dble

    !**************************************************************************

    subroutine ca_mul_inout_real( im, jm, km, inout_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm, km
      real(sp)    , intent(inout)           :: inout_arr ( im, jm, km )
      real(sp)    , intent(in   )           :: mul
      real(sp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( inout_arr( i, j, k ) .ge. minval ) &
                    .and. ( inout_arr( i, j, k ) .le. maxval ) ) then
                  inout_arr( i, j, k ) = inout_arr( i, j, k ) * mul
               else
                  inout_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_mul_inout_real

    !**************************************************************************

    subroutine ca_mul_inout_2d_real( im, jm, inout_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm
      real(sp)    , intent(inout)           :: inout_arr( im, jm )
      real(sp)    , intent(in   )           :: mul
      real(sp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: inout_arr3d( im, jm, 1 )


      inout_arr3d( :, :, 1 ) = inout_arr( :, : )

      call ca_mul( im, jm, 1, inout_arr3d, mul, &
           fillvalue, minset, maxset )

      inout_arr( :, : ) = inout_arr3d( :, :, 1 )


    end subroutine ca_mul_inout_2d_real

    !**************************************************************************

    subroutine ca_mul_inout_dble( im, jm, km, inout_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm, km
      real(dp)    , intent(inout)           :: inout_arr ( im, jm, km )
      real(dp)    , intent(in   )           :: mul
      real(dp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( inout_arr( i, j, k ) .ge. minval ) &
                    .and. ( inout_arr( i, j, k ) .le. maxval ) ) then
                  inout_arr( i, j, k ) = inout_arr( i, j, k ) * mul
               else
                  inout_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_mul_inout_dble

    !**************************************************************************

    subroutine ca_mul_inout_2d_dble( im, jm, inout_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm
      real(dp)    , intent(inout)           :: inout_arr( im, jm )
      real(dp)    , intent(in   )           :: mul
      real(dp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: inout_arr3d( im, jm, 1 )


      inout_arr3d( :, :, 1 ) = inout_arr( :, : )

      call ca_mul( im, jm, 1, inout_arr3d, mul, &
           fillvalue, minset, maxset )

      inout_arr( :, : ) = inout_arr3d( :, :, 1 )


    end subroutine ca_mul_inout_2d_dble

    !**************************************************************************

    subroutine ca_mul_real( im, jm, km, in_arr, out_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(sp)    , intent(in )           :: in_arr ( im, jm, km )
      real(sp)    , intent(out)           :: out_arr( im, jm, km )
      real(sp)    , intent(in )           :: mul
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr( i, j, k ) .ge. minval ) &
                    .and. ( in_arr( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr( i, j, k ) * mul
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_mul_real

    !**************************************************************************

    subroutine ca_mul_2d_real( im, jm, in_arr, out_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(sp)    , intent(in )           :: in_arr ( im, jm )
      real(sp)    , intent(out)           :: out_arr( im, jm )
      real(sp)    , intent(in )           :: mul
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: in_arr3d ( im, jm, 1 )
      real(sp)     :: out_arr3d( im, jm, 1 )


      in_arr3d( :, :, 1 ) = in_arr( :, : )

      call ca_mul( im, jm, 1, in_arr3d, out_arr3d, mul, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_mul_2d_real

    !**************************************************************************

    subroutine ca_mul_dble( im, jm, km, in_arr, out_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(dp)    , intent(in )           :: in_arr ( im, jm, km )
      real(dp)    , intent(out)           :: out_arr( im, jm, km )
      real(dp)    , intent(in )           :: mul
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr( i, j, k ) .ge. minval ) &
                    .and. ( in_arr( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr( i, j, k ) * mul
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_mul_dble

    !**************************************************************************

    subroutine ca_mul_2d_dble( im, jm, in_arr, out_arr, mul, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(dp)    , intent(in )           :: in_arr ( im, jm )
      real(dp)    , intent(out)           :: out_arr( im, jm )
      real(dp)    , intent(in )           :: mul
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: in_arr3d ( im, jm, 1 )
      real(dp)     :: out_arr3d( im, jm, 1 )


      in_arr3d( :, :, 1 ) = in_arr( :, : )

      call ca_mul( im, jm, 1, in_arr3d, out_arr3d, mul, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_mul_2d_dble

    !**************************************************************************

    subroutine ca_div_real( im, jm, km, in_arr, out_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(sp)    , intent(in )           :: in_arr ( im, jm, km )
      real(sp)    , intent(out)           :: out_arr( im, jm, km )
      real(sp)    , intent(in )           :: div
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr( i, j, k ) .ge. minval ) &
                    .and. ( in_arr( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr( i, j, k ) / div
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_div_real

    !**************************************************************************

    subroutine ca_div_2d_real( im, jm, in_arr, out_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(sp)    , intent(in )           :: in_arr ( im, jm )
      real(sp)    , intent(out)           :: out_arr( im, jm )
      real(sp)    , intent(in )           :: div
      real(sp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: in_arr3d ( im, jm, 1 )
      real(sp)     :: out_arr3d( im, jm, 1 )


      in_arr3d( :, :, 1 ) = in_arr( :, : )

      call ca_div( im, jm, 1, in_arr3d, out_arr3d, div, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_div_2d_real

    !**************************************************************************

    subroutine ca_div_dble( im, jm, km, in_arr, out_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm, km
      real(dp)    , intent(in )           :: in_arr ( im, jm, km )
      real(dp)    , intent(out)           :: out_arr( im, jm, km )
      real(dp)    , intent(in )           :: div
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( in_arr( i, j, k ) .ge. minval ) &
                    .and. ( in_arr( i, j, k ) .le. maxval ) ) then
                  out_arr( i, j, k ) = in_arr( i, j, k ) / div
               else
                  out_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_div_dble

    !**************************************************************************

    subroutine ca_div_2d_dble( im, jm, in_arr, out_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in )           :: im, jm
      real(dp)    , intent(in )           :: in_arr ( im, jm )
      real(dp)    , intent(out)           :: out_arr( im, jm )
      real(dp)    , intent(in )           :: div
      real(dp)    , intent(in ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: in_arr3d ( im, jm, 1 )
      real(dp)     :: out_arr3d( im, jm, 1 )


      in_arr3d( :, :, 1 ) = in_arr( :, : )

      call ca_div( im, jm, 1, in_arr3d, out_arr3d, div, &
           fillvalue, minset, maxset )

      out_arr( :, : ) = out_arr3d( :, :, 1 )


    end subroutine ca_div_2d_dble

    !**************************************************************************

    subroutine ca_div_inout_real( im, jm, km, inout_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm, km
      real(sp)    , intent(inout)           :: inout_arr( im, jm, km )
      real(sp)    , intent(in   )           :: div
      real(sp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( inout_arr( i, j, k ) .ge. minval ) &
                    .and. ( inout_arr( i, j, k ) .le. maxval ) ) then
                  inout_arr( i, j, k ) = inout_arr( i, j, k ) / div
               else
                  inout_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_div_inout_real

    !**************************************************************************

    subroutine ca_div_inout_2d_real( im, jm, inout_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm
      real(sp)    , intent(inout)           :: inout_arr( im, jm )
      real(sp)    , intent(in   )           :: div
      real(sp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(sp)     :: inout_arr3d( im, jm, 1 )


      inout_arr3d( :, :, 1 ) = inout_arr( :, : )

      call ca_div( im, jm, 1, inout_arr3d, div, &
           fillvalue, minset, maxset )

      inout_arr( :, : ) = inout_arr3d( :, :, 1 )


    end subroutine ca_div_inout_2d_real

    !**************************************************************************

    subroutine ca_div_inout_dble( im, jm, km, inout_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm, km
      real(dp)    , intent(inout)           :: inout_arr( im, jm, km )
      real(dp)    , intent(in   )           :: div
      real(dp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: fv, minval, maxval
      integer(i4b) :: i, j, k


      if( present( minset ) ) then
         minval = minset
      else
         minval = minval0
      end if
      if( present( maxset ) ) then
         maxval = maxset
      else
         maxval = maxval0
      end if
      if( present( fillvalue ) ) then
         fv = fillvalue
      else
         fv = fillvalue0
      end if


      do k = 1, km
         do j = 1, jm
            do i = 1, im
               if( ( inout_arr( i, j, k ) .ge. minval ) &
                    .and. ( inout_arr( i, j, k ) .le. maxval ) ) then
                  inout_arr( i, j, k ) = inout_arr( i, j, k ) / div
               else
                  inout_arr( i, j, k ) = fv
               end if
            end do
         end do
      end do


    end subroutine ca_div_inout_dble

    !**************************************************************************

    subroutine ca_div_inout_2d_dble( im, jm, inout_arr, div, &
         fillvalue, minset, maxset )


      integer(i4b), intent(in   )           :: im, jm
      real(dp)    , intent(inout)           :: inout_arr( im, jm )
      real(dp)    , intent(in   )           :: div
      real(dp)    , intent(in   ), optional :: fillvalue, minset, maxset


      !
      ! Local variables
      !
      real(dp)     :: inout_arr3d( im, jm, 1 )


      inout_arr3d( :, :, 1 ) = inout_arr( :, : )

      call ca_div( im, jm, 1, inout_arr3d, div, &
           fillvalue, minset, maxset )

      inout_arr( :, : ) = inout_arr3d( :, :, 1 )


    end subroutine ca_div_inout_2d_dble

    !**************************************************************************

  end module ca_module
