psmile_transform_extent.F90

Go to the documentation of this file.
00001 !------------------------------------------------------------------------
00002 ! Copyright 2010, DKRZ, Hamburg, Germany.
00003 ! All rights reserved. Use is subject to OASIS4 license terms.
00004 !------------------------------------------------------------------------
00005 
00006       ! the function stores the information given in shiftCount
00007       ! into a single integer
00008       ! the code is defined as follows
00009       ! 0000 0000 (represent the lowest 8 bits of the code)
00010       !       ^^^ number of shifts for the first dimension
00011       !      ^    sign bit for the number of shifts in the first dimension
00012       !  ^^^      number of shifts for the second dimension
00013       ! ^         sign bit for the number of shifts in the second dimension
00014       ! example:
00015       ! code = 146 ('1001 0010'B) => add 2*360 to first dimension and
00016       !                              subtract 1*180 from the second one
00017       integer function getTrCode(shiftCount)
00018          integer, intent(in) :: shiftCount(2)
00019          integer :: i
00020 
00021          getTrCode = 0
00022          do i = 2, 1, -1
00023             getTrCode = ishft(getTrCode, 4)
00024             if (shiftCount(i) < 0) getTrCode = ibset(getTrCode,3)
00025             getTrCode = getTrCode + abs(shiftCount(i))
00026          enddo
00027       end function getTrCode
00028 
00029       ! gets the shiftCount from the given code
00030       function getShiftCount(tr_code)
00031          integer, intent(in) :: tr_code
00032          integer :: getShiftCount(2)
00033          integer :: i, code
00034 
00035          code = tr_code
00036          do i = 1, 2
00037             getShiftCount(i) = iand(code,7)
00038             if (btest(code,3)) getShiftCount(i) = -1 * getShiftCount(i)
00039             code = ishft(code, -4)
00040          enddo
00041       end function getShiftCount
00042 
00043       subroutine psmile_transform_extent_cyclic (grid_type, extent, &
00044                               transformed, tr_codes, n_trans, ierror)
00045 !
00046 ! !USES:
00047 !
00048       use psmile_common, only : psmile_float_kind, ndim_3d, ch_id
00049       use psmile_grid, dummy_interface => psmile_transform_extent_cyclic
00050 
00051       implicit none
00052 
00053 !
00054 ! !INPUT PARAMETERS:
00055 !
00056 !     prism grid type of the grid containing the extent
00057       integer,                  intent (in)  :: grid_type
00058 !     Extension to be transformed and/or split
00059       real (psmile_float_kind), intent (in)  :: extent (2, ndim_3d)
00060 !
00061 ! !OUTPUT PARAMETERS:
00062 !
00063 !     Splitted and transformed parts of the extent
00064       real (psmile_float_kind), intent (out) :: transformed (2, ndim_3d, 
00065                                                              max_num_trans_parts)
00066 !     Code for the transformation performed
00067 !     used by psmile_transform_extent_back to reconstruct the original range of the parts
00068       integer, intent (out)                  :: tr_codes (max_num_trans_parts)
00069 !     Number of resulting parts splitted and/or transformed parts of extent
00070       integer, intent (out)                  :: n_trans
00071 !     Returns the error code of psmile_Transform_extent_cyclic;
00072 !             ierror = 0 : No error
00073 !             ierror > 0 : Severe error (currently not used)
00074       integer, intent (out)                  :: ierror
00075 
00076 !
00077 ! !LOCAL VARIABLES
00078 !
00079 !     control variables
00080       integer                  :: i, j
00081 !     contains information on whether the grid is cyclic in the first
00082 !     and second dimension
00083       logical                  :: isCyclic (2)
00084 !     counts number of splits for a dimension
00085       integer                  :: splitCount
00086 !     counts the number of shifts in each dimension that have to be performed
00087       integer                  :: shiftCount(2, max_num_trans_parts)
00088 !     size of a shift for each dimension (typically [360,180])
00089       real (psmile_float_kind) :: shiftSize(2)
00090 !     function declaration
00091       integer, external :: getTrCode
00092 !
00093 ! !DESCRIPTION:
00094 !
00095 ! Subroutine "psmile_Transform_extent_cyclic"
00096 !   (*) transforms the extent of a grid of a given grid type
00097 !       into the common coordinate system and
00098 !   (*) splits the extent corresponding to the cyclic behaviour of
00099 !       the given grid type
00100 !
00101 ! The routine assumes that
00102 ! (*) longitude range is within interval (-7*180:7*180)
00103 ! (*) latitude  range is within interval (-7* 90:7* 90)
00104 !
00105 ! and maps the data into the common_grid_range (see psmile_grid).
00106 
00107 #ifdef VERBOSE
00108       print 9990, trim(ch_id), extent
00109       call psmile_flushstd
00110 #endif /* VERBOSE */
00111 
00112       ! there is a isCyclic parameter given in the smioc,
00113       ! it should be taken into account as well
00114       ! checks whether the given grid type is cyclic in the first and/or
00115       ! second dimension
00116       isCyclic(1) = any(grids_cyclic_in_first_dim == grid_type)
00117       isCyclic(2) = any(grids_cyclic_in_second_dim == grid_type)
00118 
00119       ! computes the extent of the common grid range (typically [360,180])
00120       shiftSize = common_grid_range(2,1:2) - common_grid_range(1,1:2)
00121       shiftCount = 0
00122       tr_codes(:) = 0
00123       transformed(:,:,:) = 0
00124       ierror = 0
00125 
00126 #ifdef PRISM_ASSERTION
00127 !
00128 !     test input data
00129 
00130       do i = 1, 2
00131          if (isCyclic(i)) then
00132             if ((extent(2,i) - extent(1,i)) > &
00133                2*(common_grid_range(2,i) - common_grid_range(1,i))) then
00134                print *, 'index, extent(:,index)', i, extent(:,i)
00135                print *, 'range is bigger than expected range: ', &
00136                   2*(common_grid_range(2,i) - common_grid_range(1,i))
00137                call psmile_assert (__FILE__, __LINE__, &
00138                                     'extent is too big')
00139             endif
00140             if (extent (1, i) < 7 * common_grid_range(1,i) .or. &
00141                 extent (2, i) > 7 * common_grid_range(2,i)) then
00142                print *, 'index, extent', i, extent (1, i), extent (2, i)
00143                print *, 'range expected', 7 * common_grid_range(1,i), &
00144                                           7 * common_grid_range(2,i)
00145                call psmile_assert (__FILE__, __LINE__, &
00146                                    'extent is out of expected range')
00147             endif
00148             if (extent (1, i) > extent (2, i)) then
00149                print *, 'index, extent', i, extent (1, i), extent (2, i)
00150                call psmile_assert (__FILE__, __LINE__, &
00151                                    'upper and lower bound do not match')
00152             endif
00153          endif
00154       enddo
00155 
00156 #endif
00157 
00158       transformed(:, :, 1) = extent(:,:)
00159 
00160       !
00161       ! 1. performs initial shifts and checks for required splits
00162       !
00163       ! for the first and second dimension
00164       do i = 1, 2
00165          if (isCyclic(i)) then
00166             !
00167             ! shift range until lower bound of extent is within the common grid range
00168             !
00169             ! shift up (+360) if necessary
00170             do while (transformed(1, i, 1) < common_grid_range(1,i))
00171                shiftCount(i,1) = shiftCount(i,1) + 1
00172                transformed(:,i, 1) = transformed(:,i, 1) + &
00173                                      shiftSize(i)
00174             enddo
00175             ! shift down (-360) if necessary
00176             do while (transformed(1, i, 1) >= common_grid_range(2,i))
00177                shiftCount(i,1) = shiftCount(i,1) - 1
00178                transformed(:,i, 1) = transformed(:,i, 1) - &
00179                                      shiftSize(i)
00180             enddo
00181          endif
00182       enddo
00183 
00184       n_trans = 1
00185       ! generate code for the first part
00186       tr_codes(1) = getTrCode(shiftCount)
00187 
00188       !
00189       ! 2. generates additional parts and their codes if required
00190       !
00191       ! for the first and second dimension
00192       do i = 1, 2
00193          if (isCyclic(i)) then
00194 
00195             ! initiate splitCount for current dimension
00196             splitCount = 0
00197 
00198             ! while the upper boundary exceeds the common grid range
00199             do while (transformed (2, i, 1 + splitCount * n_trans) > common_grid_range(2,i))
00200 
00201                ! the parts need to be splitted
00202                ! generate new parts from copies of the existing parts
00203                transformed(:,:,1+(splitCount+1)*n_trans:(splitCount+2)*n_trans) = &
00204                   transformed(:,:,1+splitCount*n_trans:(splitCount+1)*n_trans)
00205                shiftCount(:,1+(splitCount+1)*n_trans:(splitCount+2)*n_trans) = &
00206                   shiftCount(:,1+splitCount*n_trans:(splitCount+1)*n_trans)
00207 
00208                ! truncate upper bound of the respective dimension of the original parts
00209                transformed(2,i,1+splitCount*n_trans:(splitCount+1)*n_trans) = &
00210                   common_grid_range(2,i)
00211 
00212                ! shift new parts into the common range and adjust
00213                ! shiftCount of the new parts
00214                transformed(2,i,1+(splitCount+1)*n_trans:(splitCount+2)*n_trans) = &
00215                   transformed(2,i,1+(splitCount+1)*n_trans:(splitCount+2)*n_trans) - &
00216                   shiftSize(i)
00217                shiftCount(i,1+(splitCount+1)*n_trans:(splitCount+2)*n_trans) = &
00218                   shiftCount(i,1+(splitCount+1)*n_trans:(splitCount+2)*n_trans) - 1
00219 
00220                ! truncate lower bound of the respective dimension of new parts
00221                transformed(1,i,1+(splitCount+1)*n_trans:(splitCount+2)*n_trans) = &
00222                   common_grid_range(1,i)
00223 
00224                ! generate codes for new parts
00225                do j = 1+(splitCount+1)*n_trans, (splitCount+2)*n_trans
00226                   tr_codes(j) = getTrCode(shiftCount(:,j))
00227                enddo
00228 
00229                ! increase splitCount
00230                splitCount = splitCount + 1
00231             enddo
00232 
00233             ! add the newly created parts to the number of parts
00234             n_trans = n_trans * (1 + splitCount)
00235          endif
00236       enddo
00237 
00238 #ifdef VERBOSE
00239       print 9980, trim(ch_id), ierror, n_trans
00240       call psmile_flushstd
00241 #endif /* VERBOSE */
00242 
00243 #ifdef VERBOSE
00244 
00245 9990 format (1x, a, ': psmile_transform_extent_cyclic: extent', 6e13.6)
00246 9980 format (1x, a, ': psmile_transform_extent_cyclic: eof ierror =', i3, &
00247                     '; n_trans =', i2)
00248 
00249 #endif /* VERBOSE */
00250       end subroutine psmile_Transform_extent_cyclic
00251 !
00252 !--------------------------------------------------------------------------------------------------
00253 !
00254       subroutine psmile_transform_extent_back (tr_codes, &
00255                         extents, transformed, n_trans, ierror)
00256 !
00257 ! !USES:
00258 !
00259       use psmile_common, only : psmile_float_kind, ndim_3d, ch_id
00260       use psmile_grid, dummy_interface => psmile_transform_extent_back
00261 
00262       implicit none
00263 !
00264 ! !INPUT PARAMETERS:
00265 !
00266 !     Number of sub-divided extents to be transformed
00267       integer,                  intent (in)  :: n_trans
00268 !     Info's to the extensions transformed
00269       integer,                  intent (in)  :: tr_codes (n_trans)
00270 !     Extension to be transformed and/or subdivided
00271       real (psmile_float_kind), intent (in)  :: extents (2, ndim_3d, n_trans)
00272 !
00273 ! !OUTPUT PARAMETERS:
00274 !
00275 !     Transformed extentions of "extents"
00276       real (psmile_float_kind), intent (out) :: transformed (2, ndim_3d, 
00277                                                              n_trans)
00278 !     Returns the error code of psmile_Transform_extent_back;
00279 !             ierror = 0 : No error
00280 !             ierror > 0 : Severe error (currently not used)
00281       integer,                  intent (out) :: ierror
00282 !
00283 ! !LOCAL VARIABLES
00284 !
00285 !     control variable
00286       integer :: i
00287 !     counts the number of shifts in each dimension that have to be performed
00288 !     (decoded from tr_code)
00289       integer :: shiftCount (2)
00290 !     size of a shift for each dimension (typically [360,180])
00291       integer :: shiftSize(2)
00292 !     function declaration
00293       interface
00294          function getShiftCount(tr_code)
00295             integer, intent(in) :: tr_code
00296             integer :: getShiftCount(2)
00297          end function getShiftCount
00298       end interface
00299 !
00300 ! !DESCRIPTION:
00301 !
00302 ! Subroutine "psmile_transform_extent_back" shifts the parts generated by
00303 ! psmile_transform_extent_cyclic back into their original coordinate range
00304 !
00305 #ifdef VERBOSE
00306       print 9990, trim(ch_id), n_trans
00307       call psmile_flushstd
00308 #endif /* VERBOSE */
00309 
00310       ierror = 0
00311       transformed = extents
00312       ! computes the extent of the common grid range (typically [360,180])
00313       shiftSize = common_grid_range(2,1:2) - common_grid_range(1,1:2)
00314 
00315 #ifdef PRISM_ASSERTION
00316 !
00317 !     test given input data
00318 !
00319       if (any(tr_codes(:) > 255)) then
00320          call psmile_assert (__FILE__, __LINE__, &
00321                              'invalid transformation code')
00322       endif
00323 #endif
00324 
00325       do i = 1, n_trans
00326          shiftCount = getShiftCount(tr_codes(i))
00327          transformed(1, 1:2, i) = extents(1,1:2,i) + &
00328                                   shiftCount * shiftSize * (-1.0)
00329          transformed(2, 1:2, i) = extents(2,1:2,i) + &
00330                                   shiftCount * shiftSize * (-1.0)
00331       enddo
00332 
00333 #ifdef VERBOSE
00334       print 9980, trim(ch_id), ierror
00335       call psmile_flushstd
00336 #endif /* VERBOSE */
00337 !
00338 !  Formats:
00339 !
00340 
00341 #ifdef VERBOSE
00342 
00343 9990 format (1x, a, ': psmile_transform_extent_back: n_trans', i5)
00344 9980 format (1x, a, ': psmile_transform_extent_back: eof ierror =', i3)
00345 
00346 #endif /* VERBOSE */
00347 
00348       end subroutine psmile_transform_extent_back
00349 !
00350 !--------------------------------------------------------------------------------------------------
00351 !
00352       subroutine psmile_transform_coords_db_re (tr_code_to, tr_code_from, &
00353                           coords_data_dble, coords_data_real, &
00354                           coords_size, datatype, ierror)
00355 !
00356 ! !USES:
00357 !
00358       use prism_constants
00359       use psmile_common, only : dble_vector, real_vector, &
00360                                 ndim_3d, ch_id, MPI_REAL, &
00361                                 MPI_DOUBLE_PRECISION
00362       use psmile_grid, dummy_interface => psmile_transform_coords_db_re
00363 
00364       implicit none
00365 !
00366 ! !INPUT PARAMETERS:
00367 !
00368 !     Transformation code of the part in which the data is searched
00369       integer, intent (in) :: tr_code_to
00370 !     Transformation code of the part which is sent and whose
00371 !     coordinates have to be searched.
00372       integer, intent (in) :: tr_code_from
00373 !     Number of coordinates to be searched
00374       integer, intent (in) :: coords_size (ndim_3d)
00375 !     Datatype of input data
00376       integer, intent (in) :: datatype
00377 !
00378 ! !INPUT/OUTPUT PARAMETERS:
00379 !
00380 !     Coordinates to be searched
00381       type (dble_vector), intent(inout), optional :: coords_data_dble (ndim_3d)
00382       type (real_vector), intent(inout), optional :: coords_data_real (ndim_3d)
00383 !
00384 ! !OUTPUT PARAMETERS:
00385 !
00386 !     Returns the error code of psmile_transform_coords_dble;
00387 !             ierror = 0 : No error
00388 !             ierror > 0 : Severe error (currently not used)
00389       integer, intent (out)             :: ierror
00390 !
00391 ! !LOCAL VARIABLES
00392 !
00393 !     control variable
00394       integer :: i
00395 !     counts the number of shifts in each dimension that have to be performed
00396 !     (decoded from tr_code)
00397       integer :: shiftCount (2)
00398 !     size of a shift for each dimension (typically [360,180])
00399       integer :: shiftSize(2)
00400 !     function declaration
00401       interface
00402          function getShiftCount(tr_code)
00403             integer, intent(in) :: tr_code
00404             integer :: getShiftCount(2)
00405          end function getShiftCount
00406       end interface
00407 !
00408 ! !DESCRIPTION:
00409 !
00410 ! Subroutine "psmile_transform_coords_dble" transforms the
00411 ! coordinates sent by a process to be searched into the coordinate
00412 ! range of the grid in which is searched.
00413 !
00414 #ifdef VERBOSE
00415       print 9990, trim(ch_id), tr_code_to, tr_code_from
00416       call psmile_flushstd
00417 #endif /* VERBOSE */
00418 
00419 #ifdef PRISM_ASSERTION
00420 !
00421 !     test input data
00422 !
00423       if (present(coords_data_dble) .eqv. present(coords_data_real)) then
00424          print *, 'coords_data_dble and coords_data_real are both', &
00425                   ' provided or both are missing'
00426          call psmile_assert (__FILE__, __LINE__, &
00427                               'wrong input data')
00428       endif
00429       if ((present(coords_data_dble).and.(datatype==MPI_DOUBLE_PRECISION)) .eqv. &
00430           (present(coords_data_real).and.(datatype==MPI_REAL))) then
00431          print *, 'provided data and datatype do not match'
00432          call psmile_assert (__FILE__, __LINE__, &
00433                               'wrong input data')
00434       endif
00435 #endif
00436 
00437       ierror = 0
00438 
00439       if (tr_code_to /= tr_code_from) then
00440 
00441          ! computes the extent of the common grid range (typically [360,180])
00442          shiftSize = common_grid_range(2,1:2) - common_grid_range(1,1:2)
00443 
00444          ! gets shiftCount which is required to transform the data sent
00445          ! into the common grid range
00446          shiftCount = getShiftCount(tr_code_from)
00447 
00448          ! substract the shiftCount that is required to transform the
00449          ! local data into the common grid range
00450          ! this gives the shiftCount required to transform the data sent
00451          ! into the grid range of the local process
00452          shiftCount = shiftCount - getShiftCount(tr_code_to)
00453 
00454          ! transform the data sent
00455          do i = 1, 2
00456             select case (datatype)
00457                case (MPI_DOUBLE_PRECISION)
00458                   coords_data_dble(i)%vector(1:coords_size(i)) = &
00459                      coords_data_dble(i)%vector(1:coords_size(i)) + &
00460                      shiftCount(i) * shiftSize(i)
00461                case (MPI_REAL)
00462                   coords_data_real(i)%vector(1:coords_size(i)) = &
00463                      coords_data_real(i)%vector(1:coords_size(i)) + &
00464                      shiftCount(i) * shiftSize(i)
00465             end select
00466          enddo
00467       endif
00468 
00469 #ifdef VERBOSE
00470       print 9980, trim(ch_id), ierror
00471       call psmile_flushstd
00472 #endif /* VERBOSE */
00473 
00474 #ifdef VERBOSE
00475 9990 format (1x, a, ': psmile_transform_coords_db_re: ', 2i5)
00476 9980 format (1x, a, ': psmile_transform_coords_db_re: eof ierror =', i3)
00477 #endif /* VERBOSE */
00478       end subroutine psmile_transform_coords_db_re

Generated on 18 Mar 2011 for Oasis4 by  doxygen 1.6.1