psmile_reduced_gauss_utils.F90

Go to the documentation of this file.
00001 !------------------------------------------------------------------------
00002 ! Copyright 2011, DKRZ, Hamburg, Germany.
00003 ! All rights reserved. Use is subject to OASIS4 license terms.
00004 !------------------------------------------------------------------------
00005 !
00006 ! !DESCRIPTION:
00007 !
00008 ! This file contains utility routines and functions for reduced gauss
00009 ! grids.
00010 ! psmile_init_gauss_data: initilises the data for reduced gauss grids,
00011 !                         that is stored in grids(see psmile.F90)
00012 ! psmile_gauss_gen_aux_grid : generates a reglonlatvrt auxiliary grid
00013 !                             which is used in the multigrid search
00014 !                             instead of the actual reduced gauss grid
00015 ! psmile_gauss_gen_aux_grid_map : generates a mapping between the
00016 !                                 auxiliary grid and the reduced gauss
00017 !                                 grid. this is used to translate the
00018 !                                 results from the multigrid search into
00019 !                                 reduced gauss grid coordinates
00020 ! psmile_free_aux_grid_data : frees the memory consumed by the auxiliary
00021 !                             grid and the associated map
00022 ! psmile_gauss_blockidx_to_glat: returns the global latitude of the
00023 !                                provided block index
00024 ! psmile_gauss_local_*_1d_to_3d: returns a global 3d index that corresponds
00025 !                                to the provided local 1d index
00026 ! get_gauss_neighbour_cell: returns the longitude index of cell that is
00027 !                           a neighbour to a given second longitude index.
00028 !                           (This is used in cases where the longitude rows
00029 !                           of both points have different numbers of
00030 !                           points)
00031 ! get_gauss_opposite_neighbour_cell: same as get_gauss_neighbour_cell
00032 !                                    except that this one is used in
00033 !                                    cases where both points are on
00034 !                                    different sides of a pole
00035 ! psmile_gauss_get_bicu_stencil: generates a interpolation stencil for bicubic
00036 !                                interpolation based on a global 3d start
00037 !                                location
00038 ! psmile_gauss_shift_bicu_stencil: nearly the same as
00039 !                                  psmile_gauss_get_bicu_stencil except,
00040 !                                  that the stencil return is shifted
00041 !                                  according to the provided shift-values
00042 ! psmile_gauss_get_neigh_stencil: generates a stencil which contains the
00043 !                                 point provided by the user and its 8
00044 !                                 direct neighbours
00045 ! psmile_gauss_get_bili_stencil: generates a interpolation stencil for bilinear
00046 !                                interpolation based on a global 3d start
00047 !                                location
00048 ! psmile_gauss_shift_bili_stencil: nearly the same as
00049 !                                  psmile_gauss_get_bili_stencil except,
00050 !                                  that the stencil return is shifted
00051 !                                  according to the provided shift-values
00052 ! psmile_gauss_3d_to_global_1d: transforms an array of reduced gauss 3d
00053 !                               coordinates into global 1d ones
00054 ! psmile_gauss_1d_global_to_local: transforms reduced gauss global 1d
00055 !                                  coordinates into local ones. it also
00056 !                                  takes remote points that stored
00057 !                                  locally ("remote_index"-array) into
00058 !                                  account. if a global value has no
00059 !                                  representation in the local 1d index
00060 !                                  space it is set to the fill value
00061 !                                  provided by the user.
00062 ! psmile_gauss_3d_to_local_1d: transforms reduced gauss 3d coordinates into
00063 !                              local 1d ones. it also takes remote points that
00064 !                              stored locally ("remote_index"-array) into
00065 !                              account. if a 3d value has no representation
00066 !                              in the local 1d index space it is set to the fill
00067 !                              value provided by the user.
00068 !
00069 !
00070 ! !REVISION HISTORY:
00071 !
00072 !   Date      Programmer   Description
00073 ! ----------  ----------   -----------
00074 ! 25.01.11    M. Hanke     created
00075 !
00076 !----------------------------------------------------------------------
00077 !
00078 !  $Id: psmile_reduced_gauss_utils.F90 3021 2011-03-17 09:26:03Z hanke $
00079 !  $Author: hanke $
00080 !
00081 !----------------------------------------------------------------------
00082 
00083 subroutine psmile_init_gauss_data (grid_id, nbr_points_per_lat)
00084 
00085    use psmile, only : grids
00086 
00087    implicit none
00088 
00089    integer, intent(in) :: grid_id
00090    integer, intent(in) :: nbr_points_per_lat(:)
00091 
00092    integer :: i
00093 
00094    allocate (grids(grid_id)%reduced_gauss_data%nbr_points_per_lat(size (nbr_points_per_lat)), &
00095              grids(grid_id)%reduced_gauss_data%global_lat_offsets(size (nbr_points_per_lat)))
00096 
00097    grids(grid_id)%reduced_gauss_data%nbr_points_per_lat = nbr_points_per_lat
00098 
00099    grids(grid_id)%reduced_gauss_data%global_lat_offsets(1) = 0
00100 
00101    do i = 2, size (nbr_points_per_lat)
00102       grids(grid_id)%reduced_gauss_data%global_lat_offsets(i) = &
00103          grids(grid_id)%reduced_gauss_data%global_lat_offsets(i-1) + nbr_points_per_lat(i-1)
00104    enddo
00105 
00106 end subroutine psmile_init_gauss_data
00107 
00108 !--------------------------------------------------------------------------------------------------
00109 
00110 subroutine psmile_gauss_gen_aux_grid (grid_id)
00111 
00112    use psmile_common, only : ndim_3d
00113    use psmile, only : grids, MPI_REAL, psmile_assert
00114 
00115    implicit none
00116 
00117    integer, intent(in) :: grid_id
00118 
00119    double precision :: max_size_grid_cell (ndim_3d)
00120    double precision :: local_partition_extent (2, ndim_3d)
00121 
00122    integer :: aux_grid_size (ndim_3d)
00123 
00124    double precision :: dxyz(ndim_3d)
00125 
00126    double precision, pointer :: k_corners_dble(:)
00127    real, pointer             :: k_corners_real(:)
00128 
00129    integer :: i, j
00130 
00131    ! determine the resolution required for the auxiliary grid
00132    max_size_grid_cell(1) = 360.d0 / &
00133       dble (maxval (grids(grid_id)%reduced_gauss_data%nbr_points_per_lat))
00134 
00135    max_size_grid_cell(2) = 180.d0 / &
00136       dble ( size (grids(grid_id)%reduced_gauss_data%nbr_points_per_lat))
00137 
00138    if (grids (grid_id)%corner_pointer%corner_datatype == MPI_REAL) then
00139 
00140       k_corners_real => grids (grid_id)%corner_pointer%corners_real(3)%vector
00141       max_size_grid_cell(3) = minval ( abs (k_corners_real(size(k_corners_real)/2+1:size(k_corners_real)) - &
00142                                             k_corners_real(                       1:size(k_corners_real)/2)))
00143    else
00144 
00145       k_corners_dble => grids (grid_id)%corner_pointer%corners_dble(3)%vector
00146       max_size_grid_cell(3) = minval ( abs (k_corners_dble(size(k_corners_dble)/2+1:size(k_corners_dble)) - &
00147                                             k_corners_dble(                       1:size(k_corners_dble)/2)))
00148    endif
00149 
00150    do i = 1, ndim_3d
00151       if (grids (grid_id)%corner_pointer%corner_datatype == MPI_REAL) then
00152 
00153          ! compute the extent of the local partition
00154          local_partition_extent(1, i) = minval (grids (grid_id)%corner_pointer%corners_real(i)%vector)
00155          local_partition_extent(2, i) = maxval (grids (grid_id)%corner_pointer%corners_real(i)%vector)
00156       else
00157 
00158          ! compute the extent of the local partition
00159          local_partition_extent(1, i) = minval (grids (grid_id)%corner_pointer%corners_dble(i)%vector)
00160          local_partition_extent(2, i) = maxval (grids (grid_id)%corner_pointer%corners_dble(i)%vector)
00161       endif
00162    enddo
00163 
00164 #ifdef PRISM_ASSERTION
00165    if (any (max_size_grid_cell == 0) .or. &
00166        any (local_partition_extent(2,:) - &
00167             local_partition_extent(1,:) <= 0)) then
00168 
00169          print *, "grid extent in at least one dimension is equal to 0"
00170          call psmile_assert (__FILE__, __LINE__, &
00171                              'error in grid corner data')
00172    endif
00173 #endif
00174 
00175    aux_grid_size (:) = ceiling ((local_partition_extent(2,:) - local_partition_extent(1,:)) / &
00176                                 max_size_grid_cell(:))
00177 
00178    ! at this point the resolution of the auxiliary grid is increaded by a factor of 3
00179    ! (due to the properties of reduced gauss grids a factor of 2 would be too less)
00180    ! in order to make mapping of auxiliary grid cells to the actual cell of the reduced
00181    ! gauss grid more accurate
00182    where (aux_grid_size(:) > 1) ! it makes no sense to increase resoltion if there is
00183                                 ! only one cell in the respective dimension
00184       aux_grid_size(:) = aux_grid_size(:) * 3
00185    endwhere
00186 
00187    ! compute the actual auxiliary grid
00188    allocate (grids(grid_id)%reduced_gauss_data%aux_corners(1)%vector(2*aux_grid_size(1)), &
00189              grids(grid_id)%reduced_gauss_data%aux_corners(2)%vector(2*aux_grid_size(2)), &
00190              grids(grid_id)%reduced_gauss_data%aux_corners(3)%vector(2*aux_grid_size(3)))
00191 
00192    dxyz(:) = (local_partition_extent(2,:) - local_partition_extent(1,:)) / aux_grid_size (:)
00193 
00194    do i = 1, ndim_3d
00195       grids(grid_id)%reduced_gauss_data%aux_corners(i)%vector(2*aux_grid_size(i)) = &
00196                                                                   local_partition_extent(2,i)
00197    enddo
00198 
00199    do i = 1, ndim_3d
00200       do j = 1, aux_grid_size(i)
00201 
00202          grids(grid_id)%reduced_gauss_data%aux_corners(i)%vector(j) = &
00203                local_partition_extent(1,i) + (j - 1) * dxyz(i)
00204       enddo
00205 
00206       grids(grid_id)%reduced_gauss_data%aux_corners(i)%vector(aux_grid_size(i)+1:2*aux_grid_size(i)-1) = &
00207          grids(grid_id)%reduced_gauss_data%aux_corners(i)%vector(2:aux_grid_size(i))
00208    enddo
00209 
00210 end subroutine psmile_gauss_gen_aux_grid
00211 
00212 !--------------------------------------------------------------------------------------------------
00213 
00214 subroutine psmile_gauss_gen_aux_grid_map (grid_id)
00215 
00216    use psmile_common, only : ndim_3d, dble_vector, real_vector
00217    use psmile, only        : grids, MPI_REAL
00218 
00219    implicit none
00220 
00221    integer, intent (in) :: grid_id
00222 
00223    integer :: cell_index, num_total_cells, grid_extent(2)
00224    integer :: iblock, i, j, level
00225    integer :: cell_overlap_range(2,ndim_3d)
00226 
00227    type (dble_vector), pointer :: p_aux_corners(:), p_corners_dble(:)
00228    type (real_vector), pointer :: p_corners_real(:)
00229 
00230    double precision :: cell (2, ndim_3d)
00231 
00232    p_aux_corners => grids(grid_id)%reduced_gauss_data%aux_corners
00233 
00234    if (grids (grid_id)%corner_pointer%corner_datatype == MPI_REAL) then
00235       p_corners_real => grids(grid_id)%corner_pointer%corners_real
00236    else
00237       p_corners_dble => grids(grid_id)%corner_pointer%corners_dble
00238    endif
00239 
00240    allocate (grids(grid_id)%reduced_gauss_data%aux_3d_to_local_1d_map( &
00241                size (p_aux_corners(1)%vector)/2,                       &
00242                size (p_aux_corners(2)%vector)/2,                       &
00243                size (p_aux_corners(3)%vector)/2))
00244 
00245    ! initialise with "outside"
00246    grids(grid_id)%reduced_gauss_data%aux_3d_to_local_1d_map = -1
00247 
00248    cell_index = 1
00249    num_total_cells = sum (grids(grid_id)%extent(:,1))
00250    grid_extent(:) = grids(grid_id)%grid_shape(2,1:2) - grids(grid_id)%grid_shape(1,1:2) + 1
00251 
00252    ! grid_extent(1) should be the same as grids(grid_id)%extent
00253 
00254    ! for all blocks in the local partition
00255    do iblock = 1, size (grids(grid_id)%extent, 1)
00256 
00257       ! for all horizontal level
00258       do level = 1, grid_extent(2)
00259 
00260          if (grids (grid_id)%corner_pointer%corner_datatype == MPI_REAL) then
00261             ! get extent of cell in 3rd dimension
00262             cell(:, 3) = p_corners_real(3)%vector(level:level+grid_extent(2):grid_extent(2))
00263          else
00264             ! get extent of cell in 3rd dimension
00265             cell(:, 3) = p_corners_dble(3)%vector(level:level+grid_extent(2):grid_extent(2))
00266          endif
00267 
00268          ! determine the index range of the cell in the auxiliary grid
00269          ! for the 3rd dimension
00270          cell_overlap_range (:,3) = get_matching_range (cell(:, 3), p_aux_corners(3))
00271 
00272          ! for all cells in the current block (one block only contains cells with a common latitude)
00273          do i = 1, grids(grid_id)%extent(iblock, 1)
00274 
00275             do j = 1, 2
00276 
00277                if (grids (grid_id)%corner_pointer%corner_datatype == MPI_REAL) then
00278                   ! get the extent of the cell in the 1st and 2nd dimension
00279                   cell(:, j) = p_corners_real(j)%vector(cell_index:cell_index+num_total_cells:num_total_cells)
00280                else
00281                   ! get the extent of the cell in the 1st and 2nd dimension
00282                   cell(:, j) = p_corners_dble(j)%vector(cell_index:cell_index+num_total_cells:num_total_cells)
00283                endif
00284 
00285                ! determine the index range of the cell in the auxiliary grid
00286                ! for the 1st and 2nd dimension
00287                cell_overlap_range (:,j) = get_matching_range (cell(:, j), p_aux_corners(j))
00288             enddo ! j
00289 
00290             ! set the mapping of the auxiliary to the cell
00291             grids(grid_id)%reduced_gauss_data%aux_3d_to_local_1d_map (&
00292                      cell_overlap_range(1,1):cell_overlap_range(2,1), &
00293                      cell_overlap_range(1,2):cell_overlap_range(2,2), &
00294                      cell_overlap_range(1,3):cell_overlap_range(2,3)) = cell_index
00295 
00296             ! set cell_index to the next cell
00297             cell_index = cell_index + 1
00298          enddo ! i
00299       enddo ! level
00300    enddo ! iblock
00301 
00302 contains
00303 
00304    function get_matching_range (cell_corners, grid_corners)
00305 
00306       double precision, intent (in)   :: cell_corners(2)
00307       type (dble_vector), intent (in) :: grid_corners
00308 
00309       integer :: get_matching_range(2)
00310 
00311       integer :: i, num_cells_in_grid
00312 
00313       num_cells_in_grid = size (grid_corners%vector) / 2
00314 
00315       ! determine the lower bound of the index range of the cell in the grid
00316       do i = 1, num_cells_in_grid
00317 
00318          if (grid_corners%vector(i) > cell_corners(1)) exit
00319       enddo ! i
00320       get_matching_range(1) = max (1, i-1)
00321 
00322       ! determine the upper bound of the index range of the cell in the auxiliary grid
00323       ! for the 3rd dimension
00324       do i = 1, num_cells_in_grid
00325 
00326          if (grid_corners%vector(i + num_cells_in_grid) >= cell_corners(2)) exit
00327       enddo ! i
00328       get_matching_range(2) = min (i, num_cells_in_grid)
00329 
00330    end function get_matching_range
00331 
00332 end subroutine psmile_gauss_gen_aux_grid_map
00333 
00334 !--------------------------------------------------------------------------------------------------
00335 
00336 subroutine psmile_free_aux_grid_data (grid_id)
00337 
00338    use psmile, only : grids
00339 
00340    implicit none
00341 
00342    integer, intent (in) :: grid_id
00343 
00344    deallocate (grids(grid_id)%reduced_gauss_data%aux_3d_to_local_1d_map, &
00345                grids(grid_id)%reduced_gauss_data%aux_corners(1)%vector,  &
00346                grids(grid_id)%reduced_gauss_data%aux_corners(2)%vector,  &
00347                grids(grid_id)%reduced_gauss_data%aux_corners(3)%vector)
00348 
00349 end subroutine psmile_free_aux_grid_data
00350 
00351 !--------------------------------------------------------------------------------------------------
00352 
00353 integer function psmile_gauss_blockidx_to_glat (grid_id, block_idx)
00354 
00355    use psmile, only : grids
00356 
00357    implicit none
00358 
00359    integer, intent (in) :: grid_id, block_idx
00360 
00361    integer :: block_start_offset, accu, i
00362 
00363    block_start_offset = grids(grid_id)%partition(block_idx, 1)
00364 
00365    accu = 0
00366 
00367    do i = 1, size (grids(grid_id)%reduced_gauss_data%nbr_points_per_lat)
00368 
00369       accu = accu + grids(grid_id)%reduced_gauss_data%nbr_points_per_lat(i)
00370 
00371       if (accu > block_start_offset) exit
00372    enddo
00373 
00374    psmile_gauss_blockidx_to_glat = i
00375 
00376 end function psmile_gauss_blockidx_to_glat
00377 
00378 !--------------------------------------------------------------------------------------------------
00379 
00380 function psmile_gauss_1_local_1d_to_3d (grid_id, idx)
00381 
00382    use psmile_common, only             : ndim_3d
00383    use psmile, only                    : grids
00384    use psmile_grid_reduced_gauss, only : psmile_gauss_blockidx_to_glat
00385 
00386    implicit none
00387 
00388    integer, intent (in) :: grid_id, idx
00389 
00390    integer              :: psmile_gauss_1_local_1d_to_3d (ndim_3d)
00391 
00392    integer :: lon_idx, i
00393 
00394    ! if there is additional information on the local blocks available we can
00395    ! optimise the transformation
00396    if (associated (grids(grid_id)%reduced_gauss_data%local_block_info)) then
00397 
00398       do i = 1, size (grids(grid_id)%reduced_gauss_data%local_block_info)
00399 
00400          if (idx >= grids(grid_id)%reduced_gauss_data%local_block_info(i)%local_1d_start_idx .and. &
00401              idx <= grids(grid_id)%reduced_gauss_data%local_block_info(i)%local_1d_end_idx) then
00402 
00403             psmile_gauss_1_local_1d_to_3d(:) = &
00404                grids(grid_id)%reduced_gauss_data%local_block_info(i)%global_3d_start_idx
00405 
00406             psmile_gauss_1_local_1d_to_3d(1) = psmile_gauss_1_local_1d_to_3d(1) + idx - &
00407                grids(grid_id)%reduced_gauss_data%local_block_info(i)%local_1d_start_idx
00408 
00409             exit
00410          endif
00411       enddo ! i
00412 
00413    else ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
00414 
00415       lon_idx = idx
00416 
00417       ! for all extents
00418       do i = 1, size (grids(grid_id)%extent, 1)
00419 
00420          if (lon_idx <= grids(grid_id)%extent(i,1)) exit
00421 
00422          lon_idx = lon_idx - grids(grid_id)%extent(i,1)
00423       enddo
00424 
00425       psmile_gauss_1_local_1d_to_3d(2) = psmile_gauss_blockidx_to_glat(grid_id, i)
00426       psmile_gauss_1_local_1d_to_3d(1) = lon_idx + grids(grid_id)%partition(i, 1) - &
00427          grids(grid_id)%reduced_gauss_data%global_lat_offsets(psmile_gauss_1_local_1d_to_3d(2))
00428       psmile_gauss_1_local_1d_to_3d(3) = 1
00429 
00430    endif ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
00431 
00432 end function psmile_gauss_1_local_1d_to_3d
00433 
00434 !--------------------------------------------------------------------------------------------------
00435 
00436 function psmile_gauss_n_local_1d_to_3d (grid_id, idx, num_points)
00437 
00438    use psmile_common, only             : ndim_3d
00439    use psmile, only                    : grids
00440    use psmile_grid_reduced_gauss, only : psmile_gauss_blockidx_to_glat, block_info
00441 
00442    implicit none
00443 
00444    integer, intent (in)       :: num_points
00445    integer, intent (in)       :: grid_id, idx(num_points)
00446       
00447    integer                    :: psmile_gauss_n_local_1d_to_3d (ndim_3d,num_points)
00448       
00449    integer                    :: lon_idx, i, n, curr_block, num_blocks
00450    type (block_info), pointer :: local_block_info(:)
00451 
00452 
00453    ! if there is additional information on the local blocks available we can
00454    ! optimise the transformation
00455    if (associated (grids(grid_id)%reduced_gauss_data%local_block_info)) then
00456 
00457       curr_block = 1
00458       num_blocks = size (grids(grid_id)%reduced_gauss_data%local_block_info)
00459       local_block_info => grids(grid_id)%reduced_gauss_data%local_block_info
00460 
00461 outer: do n = 1, num_points
00462 
00463          if (idx(n) >= local_block_info(curr_block)%local_1d_start_idx .and. &
00464              idx(n) <= local_block_info(curr_block)%local_1d_end_idx) then
00465 
00466             psmile_gauss_n_local_1d_to_3d(2:3,n) = &
00467                local_block_info(curr_block)%global_3d_start_idx(2:3)
00468 
00469             psmile_gauss_n_local_1d_to_3d(1,n) = &
00470                local_block_info(curr_block)%global_3d_start_idx(1) + idx(n) - &
00471                local_block_info(curr_block)%local_1d_start_idx
00472 
00473             cycle outer
00474          endif
00475 
00476          do i = curr_block+1, num_blocks, 1
00477 
00478             if (idx(n) >= local_block_info(i)%local_1d_start_idx .and. &
00479                 idx(n) <= local_block_info(i)%local_1d_end_idx) then
00480 
00481                psmile_gauss_n_local_1d_to_3d(2:3,n) = &
00482                   local_block_info(i)%global_3d_start_idx(2:3)
00483 
00484                psmile_gauss_n_local_1d_to_3d(1,n) = &
00485                   local_block_info(i)%global_3d_start_idx(1) + idx(n) - &
00486                   local_block_info(i)%local_1d_start_idx
00487 
00488                curr_block = curr_block + 1
00489                cycle outer
00490             endif
00491          enddo ! i
00492 
00493          do i = curr_block-1, 1, -1
00494 
00495             if (idx(n) >= local_block_info(i)%local_1d_start_idx .and. &
00496                 idx(n) <= local_block_info(i)%local_1d_end_idx) then
00497 
00498                psmile_gauss_n_local_1d_to_3d(2:3,n) = &
00499                   local_block_info(i)%global_3d_start_idx(2:3)
00500 
00501                psmile_gauss_n_local_1d_to_3d(1,n) = &
00502                   local_block_info(i)%global_3d_start_idx(1) + idx(n) - &
00503                   local_block_info(i)%local_1d_start_idx
00504 
00505                curr_block = curr_block - 1
00506                cycle outer
00507             endif
00508          enddo ! i
00509       enddo outer ! n
00510 
00511    else ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
00512 
00513       do n = 1, num_points
00514 
00515          lon_idx = idx(n)
00516 
00517          ! for all extents
00518          do i = 1, size (grids(grid_id)%extent, 1)
00519 
00520             if (lon_idx <= grids(grid_id)%extent(i,1)) exit
00521 
00522             lon_idx = lon_idx - grids(grid_id)%extent(i,1)
00523          enddo
00524 
00525          psmile_gauss_n_local_1d_to_3d(2,n) = psmile_gauss_blockidx_to_glat(grid_id, i)
00526          psmile_gauss_n_local_1d_to_3d(1,n) = lon_idx + grids(grid_id)%partition(i, 1) - &
00527             grids(grid_id)%reduced_gauss_data%global_lat_offsets(psmile_gauss_n_local_1d_to_3d(2,n))
00528          psmile_gauss_n_local_1d_to_3d(3,n) = 1
00529       enddo ! n
00530 
00531    endif ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
00532 
00533 end function psmile_gauss_n_local_1d_to_3d
00534 
00535 !--------------------------------------------------------------------------------------------------
00536 
00537 integer function get_gauss_neighbour_cell (idx, nbr_points_lat, nbr_points_lat_neigh)
00538 
00539    implicit none
00540 
00541    integer, intent (in) :: idx,                ! 1-based index of the cell in the latitude band
00542                            nbr_points_lat,     ! number of cells in the latitude band
00543                            nbr_points_lat_neigh ! number of cells in the latitude band for which
00544                                                 ! we search the neighbour cell index
00545 
00546    integer :: intermediate_idx
00547 
00548    if (nbr_points_lat == nbr_points_lat_neigh) then
00549       get_gauss_neighbour_cell = idx
00550       return
00551    endif
00552 
00553    ! Algorithm description:
00554    ! at first we map the points of both latitude bands to a band with
00555    ! (nbr_points_lat * nbr_points_lat_neigh * 3)
00556    ! In our intermediate latitude band we have (nbr_points_lat_neigh * 3) points for each point
00557    ! in nbr_points_lat. Our intermediate idx is a point in the middle of the point range that
00558    ! matches out given idx.
00559    ! In the end we compute the point in the latitude band which matches our intermediate index.
00560 
00561    intermediate_idx = (idx-1)*3*nbr_points_lat_neigh + nint(real(nbr_points_lat_neigh)*1.5)
00562 
00563    get_gauss_neighbour_cell = intermediate_idx / (3 * nbr_points_lat) + 1
00564 
00565 end function get_gauss_neighbour_cell
00566 
00567 !--------------------------------------------------------------------------------------------------
00568 
00569 integer function get_gauss_opposite_neighbour_cell (idx, nbr_points_lat, nbr_points_lat_neigh)
00570 
00571    implicit none
00572 
00573    integer, intent (in) :: idx,                ! 1-based index of the cell in the latitude band
00574                            nbr_points_lat,     ! number of cells in the latitude band
00575                            nbr_points_lat_neigh ! number of cells in the latitude band for which
00576                                                 ! we search the neighbour cell index
00577 
00578    integer :: intermediate_idx
00579 
00580    ! Algorithm description:
00581    ! at first we map the points of both latitude bands to a band with
00582    ! (nbr_points_lat * nbr_points_lat_neigh * 3)
00583    ! In our intermediate latitude band we have (nbr_points_lat_neigh * 3) points for each point
00584    ! in nbr_points_lat. Our intermediate idx is a point in the middle of the point range that
00585    ! matches out given idx.
00586    ! In the end we compute the point in the latitude band which matches our intermediate index.
00587 
00588    intermediate_idx = (idx-1)*3*nbr_points_lat_neigh + nint(real(nbr_points_lat_neigh)*1.5)
00589 
00590    ! get the intermedate index on the other side of the latitude band (turn 180 degree)
00591    intermediate_idx = mod(intermediate_idx + nbr_points_lat * nbr_points_lat_neigh * 3 / 2, &
00592                            nbr_points_lat * nbr_points_lat_neigh * 3)
00593 
00594    get_gauss_opposite_neighbour_cell = intermediate_idx / (3 * nbr_points_lat) + 1
00595 
00596 end function get_gauss_opposite_neighbour_cell
00597 
00598 !--------------------------------------------------------------------------------------------------
00599 
00600 function psmile_gauss_get_bicu_stencil (grid_id, base)
00601 
00602    use psmile_common, only             : ndim_3d
00603    use psmile_grid_reduced_gauss, only : psmile_gauss_shift_bicu_stencil
00604 
00605    implicit none
00606 
00607    integer, intent (in) :: grid_id, base(ndim_3d)
00608 
00609    integer :: psmile_gauss_get_bicu_stencil(ndim_3d, 16)
00610 
00611    psmile_gauss_get_bicu_stencil = psmile_gauss_shift_bicu_stencil(grid_id, base, (/0,0,0/))
00612 
00613 end function psmile_gauss_get_bicu_stencil
00614 
00615 !--------------------------------------------------------------------------------------------------
00616 
00617 function psmile_gauss_shift_bicu_stencil (grid_id, base, shift)
00618 
00619    use psmile_common, only             : ndim_3d
00620    use psmile, only                    : grids, psmile_assert
00621    use psmile_grid_reduced_gauss, only : get_gauss_opposite_neighbour_cell, &
00622                                          get_gauss_neighbour_cell
00623 
00624    implicit none
00625 
00626    integer, intent (in) :: grid_id, base (ndim_3d), shift(ndim_3d)
00627 
00628    integer :: psmile_gauss_shift_bicu_stencil (ndim_3d, 16)
00629 
00630    integer            :: global_num_lats, i, i_
00631    integer, pointer   :: g_nbr_points_per_lat(:)
00632    integer, parameter :: lon_shift(3) = (/1,2,-1/)
00633    integer            :: orientation(4)
00634 
00635    ! the points returned have the following relation to each other ("base" has index 6):
00636    !
00637    !    13  14  15  16
00638    !
00639    !     9  10  11  12
00640    !
00641    !     5   6   7   8
00642    !
00643    !     1   2   3   4
00644 
00645    g_nbr_points_per_lat => grids(grid_id)%reduced_gauss_data%nbr_points_per_lat
00646    global_num_lats = size (g_nbr_points_per_lat)
00647    orientation(:) = 1
00648 
00649 #ifdef PRISM_ASSERTION
00650    if (any (abs (shift(:)) > 1)) then
00651       call psmile_assert (__FILE__, __LINE__, &
00652                           "shifting by more than one cell is not supported")
00653    endif
00654    if (base(2)+shift(2) < 1 .or. &
00655        base(2)+shift(2) > size (g_nbr_points_per_lat)) then
00656       call psmile_assert (__FILE__, __LINE__, &
00657                           "shifting of the base point over the pole is not supported")
00658    endif
00659 #endif
00660 
00661    ! compute the second point
00662 
00663    ! if we need to recalculate the i index of the point 2
00664    if (shift(2) /= 1) then
00665    
00666       ! some special care needs to be taken in case it is on the other side of the pole
00667       if (base(2)+shift(2) == 1) then
00668 
00669             psmile_gauss_shift_bicu_stencil(1,2) =                                   &
00670                get_gauss_opposite_neighbour_cell(base(1), g_nbr_points_per_lat(1),   &
00671                                                           g_nbr_points_per_lat(1)) + &
00672                shift(1)
00673 
00674             psmile_gauss_shift_bicu_stencil(2,2) = 1
00675 
00676             orientation(1) = -1
00677       else
00678 
00679             psmile_gauss_shift_bicu_stencil(1,2) =                                &
00680                get_gauss_neighbour_cell(base(1),                                  &
00681                                         g_nbr_points_per_lat(base(2)),            &
00682                                         g_nbr_points_per_lat(base(2)-1+shift(2))) &
00683                + shift(1)
00684 
00685             psmile_gauss_shift_bicu_stencil(2,2) = base(2) - 1 + shift(2)
00686       endif
00687    else ! shift(2) == 1
00688 
00689       psmile_gauss_shift_bicu_stencil(1,2) = base(1) + shift(1)
00690       psmile_gauss_shift_bicu_stencil(2,2) = base(2)
00691    endif
00692 
00693    psmile_gauss_shift_bicu_stencil(3, 2) = base(3) + shift(3)
00694 
00695    ! compute the sixth point
00696 
00697    ! if we need to recalculate the i index of the point 6
00698    if (abs(shift(2)) == 1) then
00699    
00700       psmile_gauss_shift_bicu_stencil(1,6) =                                       &
00701          get_gauss_neighbour_cell(base(1), g_nbr_points_per_lat(base(2)),          &
00702                                            g_nbr_points_per_lat(base(2)+shift(2))) &
00703          + shift(1)
00704 
00705       psmile_gauss_shift_bicu_stencil(2,6) = base(2) + shift(2)
00706 
00707    else ! shift(2) == 0
00708 
00709       psmile_gauss_shift_bicu_stencil(1:2,6) = base(1:2) + shift(1:2)
00710    endif
00711 
00712    psmile_gauss_shift_bicu_stencil(3,6) = base(3) + shift(3)
00713 
00714    ! compute the eleventh point
00715 
00716    ! if we need to recalculate the i index of point 4
00717    if (shift(2) >= 0) then
00718 
00719       ! some special care needs to be taken in case it is on the other side of the pole
00720       if (base(2)+shift(2) == global_num_lats) then
00721 
00722             psmile_gauss_shift_bicu_stencil(1,10) =               &
00723                get_gauss_opposite_neighbour_cell(                 &
00724                   base(1), g_nbr_points_per_lat(global_num_lats), &
00725                            g_nbr_points_per_lat(global_num_lats)) &
00726                + shift(1)
00727 
00728             psmile_gauss_shift_bicu_stencil(2,10) = global_num_lats
00729 
00730             orientation(3) = -1
00731       else
00732 
00733             psmile_gauss_shift_bicu_stencil(1,10) =                               &
00734                get_gauss_neighbour_cell(base(1),                                  &
00735                                         g_nbr_points_per_lat(base(2)),            &
00736                                         g_nbr_points_per_lat(base(2)+1+shift(2))) &
00737                + shift(1)
00738 
00739             psmile_gauss_shift_bicu_stencil(2,10) = base(2) + 1 + shift(2)
00740       endif
00741 
00742    else ! shift(2) == -1
00743    
00744       psmile_gauss_shift_bicu_stencil(1,10) = base(1) + shift(1)
00745       psmile_gauss_shift_bicu_stencil(2,10) = base(2)
00746    endif
00747 
00748    psmile_gauss_shift_bicu_stencil(3,10) = base(3) + shift(3)
00749 
00750    ! compute the fourteenth point
00751 
00752    ! some special care needs to be taken in case it is on the other side of the pole
00753    if (base(2)+shift(2) == global_num_lats) then
00754 
00755          psmile_gauss_shift_bicu_stencil(1,14) =                 &
00756             get_gauss_opposite_neighbour_cell(                   &
00757                base(1), g_nbr_points_per_lat(global_num_lats),   &
00758                         g_nbr_points_per_lat(global_num_lats-1)) &
00759             + shift(1)
00760 
00761          psmile_gauss_shift_bicu_stencil(2,14) = global_num_lats-1
00762 
00763          orientation(4) = -1
00764    else if (base(2)+shift(2) == global_num_lats-1) then
00765 
00766          psmile_gauss_shift_bicu_stencil(1,14) =                 &
00767             get_gauss_opposite_neighbour_cell(                   &
00768                base(1), g_nbr_points_per_lat(global_num_lats-1), &
00769                         g_nbr_points_per_lat(global_num_lats))   &
00770             + shift(1)
00771 
00772          psmile_gauss_shift_bicu_stencil(2,14) = global_num_lats
00773 
00774          orientation(4) = -1
00775    else
00776 
00777          psmile_gauss_shift_bicu_stencil(1,14) =                               &
00778             get_gauss_neighbour_cell(base(1),                                  &
00779                                      g_nbr_points_per_lat(base(2)),            &
00780                                      g_nbr_points_per_lat(base(2)+2+shift(2))) &
00781             + shift(1)
00782 
00783          psmile_gauss_shift_bicu_stencil(2,14) = base(2) + 2 + shift(2)
00784    endif
00785 
00786    psmile_gauss_shift_bicu_stencil(3,14) = base(3) + shift(3)
00787 
00788    ! next we compute the longitude indices of the other columns
00789 
00790    do i = 2, 4
00791 
00792       ! same as i_ = mod(i,4)+1
00793       ! this will generate the indices 2,3,1
00794       i_ = iand (i, 3) + 1
00795 
00796       psmile_gauss_shift_bicu_stencil(1,i_::4) = psmile_gauss_shift_bicu_stencil(1,2::4) &
00797                                                + lon_shift(i-1) * orientation(:)
00798       psmile_gauss_shift_bicu_stencil(2:3,i_::4) = psmile_gauss_shift_bicu_stencil(2:3,2::4)
00799    enddo
00800 
00801    ! last we need to do some periodic index adjustment
00802 
00803    where (psmile_gauss_shift_bicu_stencil(1,:) < 1)
00804       psmile_gauss_shift_bicu_stencil(1,:) = psmile_gauss_shift_bicu_stencil(1,:) + &
00805                                            g_nbr_points_per_lat(psmile_gauss_shift_bicu_stencil(2,:))
00806    end where
00807 
00808    where (psmile_gauss_shift_bicu_stencil(1,:) > &
00809           g_nbr_points_per_lat(psmile_gauss_shift_bicu_stencil(2,:)))
00810       psmile_gauss_shift_bicu_stencil(1,:) = psmile_gauss_shift_bicu_stencil(1,:) - &
00811                                            g_nbr_points_per_lat(psmile_gauss_shift_bicu_stencil(2,:))
00812    end where
00813 
00814 end function psmile_gauss_shift_bicu_stencil
00815 
00816 !--------------------------------------------------------------------------------------------------
00817 
00818 function psmile_gauss_get_neigh_stencil (grid_id, base)
00819 
00820    use psmile_common, only             : ndim_3d
00821    use psmile, only                    : grids
00822    use psmile_grid_reduced_gauss, only : get_gauss_opposite_neighbour_cell, &
00823                                          get_gauss_neighbour_cell
00824 
00825    implicit none
00826 
00827    integer, intent (in) :: grid_id, base(ndim_3d)
00828 
00829    integer :: psmile_gauss_get_neigh_stencil(ndim_3d, 9)
00830 
00831    integer            :: global_num_lats, i
00832    integer, pointer   :: g_nbr_points_per_lat(:)
00833    integer, parameter :: lon_shift(3) = (/-1,0,1/)
00834 
00835    ! the points returned have the following relation to each other ("base" has index 5):
00836    !
00837    !     7   8   9
00838    !
00839    !     4   5   6
00840    !
00841    !     1   2   3
00842 
00843    g_nbr_points_per_lat => grids(grid_id)%reduced_gauss_data%nbr_points_per_lat
00844    global_num_lats = size (g_nbr_points_per_lat)
00845 
00846    psmile_gauss_get_neigh_stencil(3, :) = base(3)
00847    psmile_gauss_get_neigh_stencil(:, 5) = base
00848 
00849    ! at first we compute the latitudes of all four rows
00850 
00851    psmile_gauss_get_neigh_stencil(2,1:3) = max (base(2)-1, 1)
00852       ! lat index of southern neighbours (if we are on the south pole
00853       ! then our neighbour is on the other side of the pole)
00854    psmile_gauss_get_neigh_stencil(2,4:6) = base(2)
00855       ! lat index of the base latitude
00856    psmile_gauss_get_neigh_stencil(2,7:9) = min (base(2)+1, global_num_lats)
00857       ! latitude index of northern neighbours (if we are on the
00858       ! north pole then our neighbour is on the other side
00859       ! of the pole)
00860 
00861    ! at second we compute the longitude indices of the base column (2,10,14)
00862 
00863    do i = 2, 8, 6
00864 
00865       ! if the point is supposed to be on the other side of the pole
00866       if (base(2) == psmile_gauss_get_neigh_stencil(2,i)) then
00867 
00868          psmile_gauss_get_neigh_stencil(1,i) =                           &
00869             get_gauss_opposite_neighbour_cell(base(1),                   &
00870                                           g_nbr_points_per_lat(base(2)), &
00871                                           g_nbr_points_per_lat(psmile_gauss_get_neigh_stencil(2,i)))
00872       else
00873 
00874          psmile_gauss_get_neigh_stencil(1,i) =                      &
00875             get_gauss_neighbour_cell(base(1),                       &
00876                                      g_nbr_points_per_lat(base(2)), &
00877                                      g_nbr_points_per_lat(psmile_gauss_get_neigh_stencil(2,i)))
00878       endif
00879 
00880    enddo
00881 
00882    ! next we compute the longitude indices of the other columns
00883 
00884    do i = 1, 3, 2
00885 
00886       psmile_gauss_get_neigh_stencil(1,i::3) = psmile_gauss_get_neigh_stencil(1,2::3) + lon_shift(i)
00887    enddo
00888 
00889    ! last we need to do some periodic index adjustment
00890 
00891    where (psmile_gauss_get_neigh_stencil(1,:) < 1)
00892       psmile_gauss_get_neigh_stencil(1,:) = psmile_gauss_get_neigh_stencil(1,:) + &
00893                                            g_nbr_points_per_lat(psmile_gauss_get_neigh_stencil(2,:))
00894    end where
00895 
00896    where (psmile_gauss_get_neigh_stencil(1,:) > &
00897           g_nbr_points_per_lat(psmile_gauss_get_neigh_stencil(2,:)))
00898       psmile_gauss_get_neigh_stencil(1,:) = psmile_gauss_get_neigh_stencil(1,:) - &
00899                                            g_nbr_points_per_lat(psmile_gauss_get_neigh_stencil(2,:))
00900    end where
00901 
00902 end function psmile_gauss_get_neigh_stencil
00903 
00904 !--------------------------------------------------------------------------------------------------
00905 
00906 function psmile_gauss_get_bili_stencil (grid_id, base)
00907 
00908    use psmile_common, only             : ndim_3d
00909    use psmile_grid_reduced_gauss, only : psmile_gauss_shift_bili_stencil
00910 
00911    implicit none
00912 
00913    integer, intent (in) :: grid_id, base(ndim_3d)
00914 
00915    integer :: psmile_gauss_get_bili_stencil(ndim_3d, 4)
00916 
00917 
00918    psmile_gauss_get_bili_stencil = psmile_gauss_shift_bili_stencil (grid_id, base, (/0,0,0/))
00919 
00920 end function psmile_gauss_get_bili_stencil
00921 
00922 !--------------------------------------------------------------------------------------------------
00923 
00924 function psmile_gauss_shift_bili_stencil (grid_id, base, shift)
00925 
00926    use psmile_common, only             : ndim_3d
00927    use psmile, only                    : grids, psmile_assert
00928    use psmile_grid_reduced_gauss, only : get_gauss_opposite_neighbour_cell, &
00929                                          get_gauss_neighbour_cell
00930 
00931    implicit none
00932 
00933    integer, intent (in) :: grid_id, base (ndim_3d), shift(ndim_3d)
00934 
00935    integer :: psmile_gauss_shift_bili_stencil (ndim_3d, 4)
00936 
00937    integer            :: global_num_lats
00938    integer, pointer   :: g_nbr_points_per_lat(:)
00939    integer            :: orientation
00940 
00941    ! the points returned have the following relation to each other ("base" has index 6):
00942    !
00943    !     4   3
00944    !
00945    !     1   2
00946 
00947    g_nbr_points_per_lat => grids(grid_id)%reduced_gauss_data%nbr_points_per_lat
00948    global_num_lats = size (g_nbr_points_per_lat)
00949    orientation = 1
00950 
00951 #ifdef PRISM_ASSERTION
00952    if (any (abs (shift(:)) > 1)) then
00953       call psmile_assert (__FILE__, __LINE__, &
00954                           "shifting by more than one cell is not supported")
00955    endif
00956    if (base(2)+shift(2) < 1 .or. &
00957        base(2)+shift(2) > size (g_nbr_points_per_lat)) then
00958       call psmile_assert (__FILE__, __LINE__, &
00959                           "shifting of the base point over the pole is not supported")
00960    endif
00961 #endif
00962 
00963    ! compute the first point
00964 
00965    ! if we need to recalculate the i index of point 1
00966    if (abs(shift(2)) == 1) then
00967    
00968       psmile_gauss_shift_bili_stencil(1,1) =                                         &
00969          get_gauss_neighbour_cell(base(1), g_nbr_points_per_lat(base(2)),          &
00970                                            g_nbr_points_per_lat(base(2)+shift(2))) &
00971          + shift(1)
00972 
00973       psmile_gauss_shift_bili_stencil(2,1) = base(2) + shift(2)
00974 
00975    else ! shift(2) == 0
00976 
00977       psmile_gauss_shift_bili_stencil(1:2,1) = base(1:2) + shift(1:2)
00978    endif
00979 
00980    psmile_gauss_shift_bili_stencil(3,1) = base(3) + shift(3)
00981 
00982    ! compute the fourth point
00983 
00984    ! if we need to recalculate the i index of point 4
00985    if (shift(2) >= 0) then
00986 
00987       ! some special care needs to be taken in case it is on the other side of the pole
00988       if (base(2)+shift(2) == global_num_lats) then
00989 
00990             psmile_gauss_shift_bili_stencil(1,4) =                &
00991                get_gauss_opposite_neighbour_cell(                 &
00992                   base(1), g_nbr_points_per_lat(global_num_lats), &
00993                            g_nbr_points_per_lat(global_num_lats)) &
00994                + shift(1)
00995 
00996             psmile_gauss_shift_bili_stencil(2,4) = global_num_lats
00997 
00998             orientation = -1
00999       else
01000 
01001             psmile_gauss_shift_bili_stencil(1,4) =                                &
01002                get_gauss_neighbour_cell(base(1),                                  &
01003                                         g_nbr_points_per_lat(base(2)),            &
01004                                         g_nbr_points_per_lat(base(2)+1+shift(2))) &
01005                + shift(1)
01006 
01007             psmile_gauss_shift_bili_stencil(2,4) = base(2) + 1 + shift(2)
01008       endif
01009 
01010    else ! shift(2) == -1
01011    
01012       psmile_gauss_shift_bili_stencil(1,4) = base(1) + shift(1)
01013       psmile_gauss_shift_bili_stencil(2,4) = base(2)
01014    endif
01015 
01016    psmile_gauss_shift_bili_stencil(3,4) = base(3) + shift(3)
01017 
01018    ! compute the second and third point
01019    psmile_gauss_shift_bili_stencil(:,2) = psmile_gauss_shift_bili_stencil(:,1) + (/1,0,0/) 
01020    psmile_gauss_shift_bili_stencil(:,3) = psmile_gauss_shift_bili_stencil(:,4) + &
01021                                           (/orientation,0,0/)
01022    
01023    ! last we need to do some periodic index adjustment
01024    where (psmile_gauss_shift_bili_stencil(1,:) < 1)
01025       psmile_gauss_shift_bili_stencil(1,:) = psmile_gauss_shift_bili_stencil(1,:) + &
01026                                           g_nbr_points_per_lat(psmile_gauss_shift_bili_stencil(2,:))
01027    end where
01028 
01029    where (psmile_gauss_shift_bili_stencil(1,:) > &
01030          g_nbr_points_per_lat(psmile_gauss_shift_bili_stencil(2,:)))
01031       psmile_gauss_shift_bili_stencil(1,:) = psmile_gauss_shift_bili_stencil(1,:) - &
01032                                           g_nbr_points_per_lat(psmile_gauss_shift_bili_stencil(2,:))
01033    end where
01034 
01035 end function psmile_gauss_shift_bili_stencil
01036 
01037 !--------------------------------------------------------------------------------------------------
01038 
01039 function psmile_gauss_3d_to_global_1d (grid_id, points_3d, num_points)
01040 
01041    use psmile_common, only : ndim_3d
01042    use psmile, only        : grids
01043 
01044    implicit none
01045 
01046    integer, intent(in) :: grid_id, num_points
01047    integer, intent(in) :: points_3d(ndim_3d, num_points)
01048 
01049    integer :: psmile_gauss_3d_to_global_1d(num_points)
01050 
01051    integer :: i, num_lats
01052 
01053    num_lats = size (grids(grid_id)%reduced_gauss_data%nbr_points_per_lat)
01054 
01055    do i = 1, num_points
01056 
01057       if ((points_3d(2,i) == 1) .or. (points_3d(2,i) > num_lats)) then
01058 
01059          psmile_gauss_3d_to_global_1d(i) = points_3d(1,i)
01060 
01061       else
01062 
01063          if (points_3d(1,i) >= 1 .and. &
01064              points_3d(1,i) <= grids(grid_id)%reduced_gauss_data%nbr_points_per_lat(points_3d(2,i))) then
01065              
01066             psmile_gauss_3d_to_global_1d(i) = points_3d(1,i) + &
01067                sum (grids(grid_id)%reduced_gauss_data%nbr_points_per_lat(1:points_3d(2,i)-1))
01068          else
01069             psmile_gauss_3d_to_global_1d(i) = points_3d(1,i)
01070          endif
01071       endif
01072    enddo
01073 
01074 end function psmile_gauss_3d_to_global_1d
01075 
01076 !--------------------------------------------------------------------------------------------------
01077 
01078 function psmile_gauss_1d_global_to_local (grid_id, points_1d, num_points, &
01079                                           fill_value, inc_remote_neigh)
01080 
01081    use psmile, only        : grids
01082 
01083    implicit none
01084 
01085    integer, intent(in)           :: grid_id, num_points, fill_value
01086    integer, intent(in)           :: points_1d(num_points)
01087    logical, intent(in), optional :: inc_remote_neigh ! is this routine supposed to
01088                                                      ! include the remote points of
01089                                                      ! which this processes has a
01090                                                      ! local copy
01091 
01092    integer :: psmile_gauss_1d_global_to_local(num_points)
01093 
01094    integer :: i, j, num_local_points, curr_block
01095 
01096    psmile_gauss_1d_global_to_local(:) = fill_value
01097 
01098    if (associated (grids(grid_id)%reduced_gauss_data%local_block_info)) then
01099 
01100       curr_block = 1
01101 
01102       ! for all points
01103    outer: do i = 1, num_points
01104 
01105          do j = curr_block, size (grids(grid_id)%partition, 1)
01106 
01107             if (points_1d(i) >= &
01108                 grids(grid_id)%reduced_gauss_data%local_block_info(j)%global_1d_start_idx &
01109                 .and. &
01110                 points_1d(i) <= &
01111                 grids(grid_id)%reduced_gauss_data%local_block_info(j)%global_1d_end_idx) then
01112 
01113                psmile_gauss_1d_global_to_local(i) = &
01114                   grids(grid_id)%reduced_gauss_data%local_block_info(j)%local_1d_start_idx + &
01115                   points_1d(i) - &
01116                   grids(grid_id)%reduced_gauss_data%local_block_info(j)%global_1d_start_idx
01117 
01118                curr_block = j
01119                cycle outer
01120             endif
01121          enddo
01122 
01123          do j = 1, curr_block-1
01124 
01125             if (points_1d(i) >= &
01126                 grids(grid_id)%reduced_gauss_data%local_block_info(j)%global_1d_start_idx &
01127                 .and. &
01128                 points_1d(i) <= &
01129                 grids(grid_id)%reduced_gauss_data%local_block_info(j)%global_1d_end_idx) then
01130 
01131                psmile_gauss_1d_global_to_local(i) = &
01132                   grids(grid_id)%reduced_gauss_data%local_block_info(j)%local_1d_start_idx + &
01133                   points_1d(i) - &
01134                   grids(grid_id)%reduced_gauss_data%local_block_info(j)%global_1d_start_idx
01135 
01136                curr_block = j
01137                cycle outer
01138             endif
01139          enddo
01140       enddo outer ! i
01141 
01142    else ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
01143 
01144       ! for all blocks in the local partition
01145       do i = 1, size (grids(grid_id)%partition, 1)
01146       
01147          ! look for points that are in the current block and transform them to local indices
01148          where (points_1d(:) > grids(grid_id)%partition(i,1) .and. &
01149                points_1d(:) <= grids(grid_id)%partition(i,1) + grids(grid_id)%extent(i,1))
01150       
01151             psmile_gauss_1d_global_to_local(:) = points_1d(:) - &
01152                                                 grids(grid_id)%partition(i,1) + &
01153                                                 sum (grids(grid_id)%extent(1:i-1,1))
01154       
01155          end where
01156       
01157       enddo
01158 
01159    endif ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
01160 
01161    ! if the user specified that the locally stored remote points
01162    ! are not to be taken into account -> return
01163    if (present(inc_remote_neigh)) then
01164       if (.not. inc_remote_neigh) return
01165    endif
01166 
01167    ! if we have some data on remote points stored locally
01168    if (associated (grids(grid_id)%remote_index)) then
01169 
01170       num_local_points = sum (grids(grid_id)%extent(:,1))
01171 
01172       ! for all points which were not found in the local partitions
01173 outer2:do i = 1, num_points
01174 
01175          if (psmile_gauss_1d_global_to_local(i) == fill_value) then
01176 
01177             do j = 1, size (grids(grid_id)%remote_index)
01178 
01179                if (points_1d(i) == grids(grid_id)%remote_index(j)) then
01180 
01181                   psmile_gauss_1d_global_to_local(i) = j + num_local_points
01182                   cycle outer2
01183 
01184                endif
01185             enddo ! j
01186          endif
01187       enddo outer2 ! i
01188    endif
01189 
01190 end function psmile_gauss_1d_global_to_local
01191 
01192 !--------------------------------------------------------------------------------------------------
01193 
01194 function psmile_gauss_3d_to_local_1d (grid_id, points_3d, num_points, &
01195                                           fill_value, inc_remote_neigh)
01196 
01197    use psmile, only                    : grids
01198    use psmile_common, only             : ndim_3d
01199    use psmile_grid_reduced_gauss, only : psmile_gauss_3d_to_global_1d, &
01200                                          psmile_gauss_1d_global_to_local, &
01201                                          block_info
01202 
01203    implicit none
01204 
01205    integer, intent(in)           :: grid_id, num_points, fill_value
01206    integer, intent(in)           :: points_3d(ndim_3d, num_points)
01207    logical, intent(in), optional :: inc_remote_neigh ! is this routine supposed to
01208                                                      ! include the remote points of
01209                                                      ! which this processes has a
01210                                                      ! local copy
01211 
01212    integer :: psmile_gauss_3d_to_local_1d(num_points)
01213 
01214    integer                    :: i, j, num_blocks, num_local_points
01215    integer                    :: point_global_1d(1)
01216    type (block_info), pointer :: local_block_info (:)
01217 
01218    ! if there is additional information on the local blocks available we can
01219    ! optimise the transformation
01220    if (associated (grids(grid_id)%reduced_gauss_data%local_block_info)) then
01221 
01222        psmile_gauss_3d_to_local_1d = fill_value
01223        local_block_info => grids(grid_id)%reduced_gauss_data%local_block_info
01224        num_blocks = size (local_block_info)
01225 
01226 !       do n = 1, num_points
01227 !         do i = 1 , num_blocks
01228  
01229 !            if (points_3d(1, n) >= local_block_info(i)%global_3d_start_idx(1) .and. &
01230 !                points_3d(1, n) <= local_block_info(i)%global_3d_end_idx(1) .and.   &
01231 !                points_3d(2, n) == local_block_info(i)%global_3d_start_idx(2)) then
01232  
01233 !               psmile_gauss_3d_to_local_1d(n) =                &
01234 !                  local_block_info(i)%local_1d_start_idx +     &
01235 !                  points_3d(1, n) -                            &
01236 !                  local_block_info(i)%global_3d_start_idx(1)
01237 !               exit
01238 !            endif    
01239 !         enddo ! i
01240 !       enddo ! n
01241       do i = 1 , num_blocks
01242 
01243          where (points_3d(1, :) >= local_block_info(i)%global_3d_start_idx(1) .and. &
01244                 points_3d(1, :) <= local_block_info(i)%global_3d_end_idx(1) .and.   &
01245                 points_3d(2, :) == local_block_info(i)%global_3d_start_idx(2))
01246 
01247             psmile_gauss_3d_to_local_1d(:) =                &
01248                local_block_info(i)%local_1d_start_idx +     &
01249                points_3d(1, :) -                            &
01250                local_block_info(i)%global_3d_start_idx(1)
01251          endwhere    
01252       enddo ! i
01253 
01254       if (present(inc_remote_neigh)) then
01255 
01256          if (inc_remote_neigh) then
01257 
01258             num_local_points = sum (grids(grid_id)%extent(:,1))
01259 
01260 outer:      do i = 1, num_points
01261 
01262                if  (psmile_gauss_3d_to_local_1d(i) == fill_value) then
01263 
01264                   point_global_1d = psmile_gauss_3d_to_global_1d(grid_id, (/points_3d(:, i)/), 1)
01265 
01266                   do j = 1, size (grids(grid_id)%remote_index)
01267 
01268                      if (point_global_1d(1) == grids(grid_id)%remote_index(j)) then
01269 
01270                         psmile_gauss_3d_to_local_1d(i) = j + num_local_points
01271                         cycle outer
01272 
01273                      endif
01274                   enddo ! j
01275                endif
01276             enddo outer
01277          endif ! inc_remote_neigh
01278       endif ! present(inc_remote_neigh)
01279 
01280    else ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
01281 
01282       if (present(inc_remote_neigh)) then
01283          psmile_gauss_3d_to_local_1d = psmile_gauss_1d_global_to_local (grid_id,     &
01284                                           psmile_gauss_3d_to_global_1d (grid_id,     &
01285                                                                         points_3d,   &
01286                                                                         num_points), &
01287                                           num_points, fill_value, inc_remote_neigh)
01288       else
01289          psmile_gauss_3d_to_local_1d = psmile_gauss_1d_global_to_local (grid_id,     &
01290                                           psmile_gauss_3d_to_global_1d (grid_id,     &
01291                                                                         points_3d,   &
01292                                                                         num_points), &
01293                                           num_points, fill_value)
01294       endif
01295    endif ! associated (grids(grid_id)%reduced_gauss_data%local_block_info)
01296 
01297 end function psmile_gauss_3d_to_local_1d

Generated on 18 Mar 2011 for Oasis4 by  doxygen 1.6.1