psmile_global_search_nnx_real.F90

Go to the documentation of this file.
00001 !-----------------------------------------------------------------------
00002 ! Copyright 2006-2010, NEC Europe Ltd., London, UK.
00003 ! All rights reserved. Use is subject to OASIS4 license terms.
00004 !-----------------------------------------------------------------------
00005 !BOP
00006 !
00007 ! !ROUTINE: PSMILe_global_search_nnx_real
00008 !
00009 ! !INTERFACE:
00010 
00011       subroutine psmile_global_search_nnx_real (comp_info, search,        &
00012                         var_id, tgt_coords_x, tgt_coords_y, tgt_coords_z, &
00013                         neighbors_3d, nloc, num_neigh, nb_extra,          &
00014                         extra_search, send_index,                         &
00015                         ierror)
00016 !
00017 ! !USES:
00018 !
00019       use PRISM
00020 !
00021       use psmile_grid, only : psmile_transform_extent_cyclic, &
00022                               psmile_transform_extent_back, &
00023                               max_num_trans_parts, &
00024                               code_no_trans, &
00025                               common_grid_range
00026 !
00027       use PSMILe, dummy_interface => PSMILe_global_search_nnx_real
00028 
00029       Implicit none
00030 !
00031 ! !INPUT PARAMETERS:
00032 
00033       Type (Enddef_comp), Intent (In) :: comp_info
00034 !
00035 !     Info on the component in which the donor cells
00036 !     should be searched.
00037 !
00038       Type (Enddef_search), Intent (InOut) :: search
00039 
00040 !     Info's on coordinates to be searched
00041 
00042       Integer,            Intent (In) :: var_id
00043 
00044 !     Handle to the grid function
00045 
00046       Integer,            Intent (In) :: send_index
00047 
00048 !     Send index of coupler send for the method and coordinates
00049 
00050       Integer,            Intent (In) :: nloc
00051 !
00052 !     Total  Number of locations to be transferred
00053 !
00054       Real,   Intent (In)             :: tgt_coords_x (nloc)
00055       Real,   Intent (In)             :: tgt_coords_y (nloc)
00056       Real,   Intent (In)             :: tgt_coords_z (nloc)
00057 
00058 !     Coordinates of the target points (which were searched and found)
00059 !
00060       Integer,            Intent (In) :: num_neigh
00061 !
00062 !     Last dimension of neighbors array "neighbors_3d" and
00063 !     number of neighbors to be searched.
00064 !     besser n_corners
00065 
00066       Integer,            Intent (In) :: nb_extra
00067 !
00068 !     Number of nearest neigbhbours to be searched per extra point
00069 !
00070 ! !INPUT/OUTPUT PARAMETERS:
00071 !
00072       Integer,            Intent (InOut) :: neighbors_3d (ndim_3d, nloc, 
00073                                                           num_neigh)
00074 
00075 !     Indices of neighbor locations (interpolation bases)
00076 !
00077       Type (Extra_search_info), Intent (InOut) :: extra_search
00078 !
00079 !     Number of locations where
00080 !       (*) required mask values were not true
00081 
00082 ! !OUTPUT PARAMETERS:
00083 !
00084       Integer,           Intent (Out) :: ierror
00085 
00086 !     Returns the error code of PSMILe_global_search_nnx_real;
00087 !             ierror = 0 : No error
00088 !             ierror > 0 : Severe error
00089 !
00090 ! !LOCAL PARAMETERS
00091 !
00092 !  DBLE_EARTH = Earth radius in meter
00093 !
00094 !  LEN_ITEM = Number of pieces of information
00095 !             in integer buffer "ibuf"
00096 !             1: index in indices/dist_real/send_mask
00097 !  INLP_LEN = Inner loop length for optimization
00098 !  lon   = Index of Longitudes in arrays "boxes"
00099 !  lat   = Index of Latitudes  in arrays "boxes"
00100 !  vrt   = Index of height     in arrays "boxes"
00101 !
00102 !
00103       Real, Parameter                 :: real_earth = 6400000.0d0
00104 !
00105       Integer, Parameter              :: len_item = 1
00106 !
00107       Integer, Parameter              :: inlp_len = 256
00108 !
00109       Integer, Parameter              :: lon = 1
00110       Integer, Parameter              :: lat = 2
00111       Integer, Parameter              :: vrt = 3
00112 !
00113 !
00114 ! !LOCAL VARIABLES
00115 !
00116 !     ... Method pointer
00117 !
00118       Integer                         :: comp_id, grid_id
00119       Integer                         :: global_grid_id
00120       Integer, Pointer                :: indices (:)
00121 !
00122 !     ... Info's on actual component
00123 !
00124       Integer                         :: igrid, rank
00125       Integer                         :: n_total
00126       Integer                         :: grid_type
00127       Real (PSMILe_float_kind), Pointer :: extents (:, :, :)
00128 !
00129 !     ... lookup table
00130 !
00131       Integer, allocatable            :: igrid_to_dest_comp(:)
00132 !
00133 !     ... loop variables
00134 !
00135       Integer                         :: j, n
00136       Integer                         :: ibeg, iend
00137 !
00138 !     ... for data to other processes
00139 !
00140       Logical                         :: mask_changed
00141       Integer                         :: n_extra
00142 !
00143       Logical, Allocatable            :: send_mask (:)
00144       Real, Allocatable               :: boxes (:, :, :)
00145       Real (PSMILe_float_kind)        :: range_box (2, ndim_3d)
00146       Real (PSMILe_float_kind)        :: dist_max (2)
00147       Real                            :: real_huge
00148 !
00149 !     ... For locations controlled
00150 !
00151 !     Real, Pointer                   :: sin_search (:, :)
00152 !     Real, Pointer                   :: cos_search (:, :)
00153 !     Real, Pointer                   :: z_search (:)
00154       Real, Pointer                   :: dist_real (:, :)
00155       Real                            :: r_earth2, r_lat
00156       Real                            :: delta, sin_d, cos_lat
00157 !
00158 !     ... transformed faces
00159 !
00160       Integer                         :: n_trans, n_int
00161 !
00162       Integer                         :: tr_codes (max_num_trans_parts)
00163       Integer                         :: found (max_num_trans_parts)
00164       Real (PSMILe_float_kind)        :: dinter_trans (2, ndim_3d)
00165       Real (PSMILe_float_kind)        :: transformed (2, ndim_3d, 
00166                                                       max_num_trans_parts), 
00167                                          dinter (2, ndim_3d, max_num_trans_parts)
00168 !
00169       Real, Save                      :: period2 (ndim_3d)
00170 !
00171 !     ... for points found
00172 !
00173       Integer                         :: n_found, n_liste
00174       Integer                         :: ip_dist
00175 !
00176 !     ... for send to partners
00177 !
00178       Type (Send_information), Pointer :: send_info
00179       Integer                         :: extra_msg (nd_msgextra)
00180 !
00181       Integer                         :: i, ip, ipi, ireq
00182       Integer                         :: len_ibuf, ndibuf, n_send
00183       Integer                         :: len_rbuf, len_rtem, ndrbuf
00184       Integer, Allocatable            :: ibuf (:)
00185       Real, Pointer                   :: buf (:)
00186 !
00187 !     ... for recv from partners
00188 !
00189       Integer                         :: answer (nd_msgextra)
00190       Integer, Allocatable            :: selected (:, :)
00191       Type (Select_search_info), Pointer  :: sel_info (:)
00192 !
00193 !     ... for communication
00194 !
00195       Integer                         :: dest, index, dest_comp, sender
00196       Integer                         :: nrecv, n_recv_req
00197       Integer                         :: recv_req
00198       Integer                         :: save_lreq (2:3)
00199       Integer                         :: status (MPI_STATUS_SIZE)
00200 !
00201 !     ... for error handling
00202 !
00203       Integer, Parameter              :: nerrp = 3
00204       Integer                         :: ierrp (nerrp)
00205 !
00206 ! !DESCRIPTION:
00207 !
00208 ! Subroutine "PSMILe_global_search_nnx_real" performs a global 
00209 ! nearest neighbour search for the interpolation points 
00210 ! which require an extra seach.
00211 !
00212 ! TODO: Save buffer indices in indices/send_mask/dist_real (see len_item)
00213 !       locally instead of passing them !!!
00214 !
00215 ! !REVISION HISTORY:
00216 !
00217 !   Date      Programmer   Description
00218 ! ----------  ----------   -----------
00219 ! 09.10.06    H. Ritzdorf  created
00220 !
00221 !EOP
00222 !----------------------------------------------------------------------
00223 !
00224 !  $Id: psmile_global_search_nnx_real.F90 2935 2011-02-03 07:52:41Z redler $
00225 !  $Author: redler $
00226 !
00227    Character(len=len_cvs_string), save :: mycvs = 
00228        '$Id: psmile_global_search_nnx_real.F90 2935 2011-02-03 07:52:41Z redler $'
00229 !
00230 !----------------------------------------------------------------------
00231 !
00232 !  Initialization
00233 !
00234 #ifdef VERBOSE
00235       print 9990, trim(ch_id), var_id, search%msg_intersections%first_tgt_method_id, search%sender
00236 #endif /* VERBOSE */
00237 
00238       call psmile_flushstd
00239 !
00240       ierror = 0
00241 !
00242       ndrbuf = 0
00243       ndibuf = 0
00244       n_recv_req = 0
00245 !
00246       r_earth2 = 1.0 / (real_earth * 2.0)
00247       r_lat = 1.0 / (real_earth * real_deg2rad)
00248 !
00249       period2 = (common_grid_range(2,:) - common_grid_range(1,:)) / 2.0d0
00250 !
00251       grid_id        = Methods(Fields(var_id)%method_id)%grid_id
00252       global_grid_id = Grids(grid_id)%global_grid_id
00253       grid_type      = Grids(grid_id)%grid_type
00254 !
00255       comp_id = comp_info%comp_id
00256 !
00257 ! Uebergeben oder ein-dimensional
00258 !
00259       send_info => Methods(Fields(var_id)%method_id)%send_infos_coupler(send_index)
00260 !
00261       indices    => extra_search%indices
00262       dist_real  => extra_search%dist_real
00263 !
00264       n_extra = extra_search%n_extra
00265 !
00266 #ifdef PRISM_ASSERTION
00267 #ifdef HUHU
00268       sin_search => extra_search%sin_search_real
00269       cos_search => extra_search%cos_search_real 
00270         z_search => extra_search%z_search_real
00271       if ( .not. Associated (extra_search%dist_real)       .or. &
00272            .not. Associated (extra_search%cos_search_real) .or. &
00273            .not. Associated (extra_search%sin_search_real) .or. &
00274            .not. Associated (extra_search%z_search_real)   ) then
00275 #else
00276       if ( .not. Associated (extra_search%dist_real) ) then
00277 #endif
00278 !
00279          call psmile_assert (__FILE__, __LINE__, &
00280                              "arrays should be allocated and set")
00281       endif
00282 #endif
00283 !
00284 !  Rank of actual process in Component communicator
00285 !
00286       rank    = Comps(comp_id)%rank
00287 !
00288 ! n_total   = Total number of grids/extents       in array "all_extents"
00289 ! igrid_end = Last  grid/extent of actual process in array "all_extents"
00290 ! igrid     = Index of actual grid in array "all_extents"
00291 !
00292       extents => comp_info%all_extents
00293 !
00294       n_total   = SUM (comp_info%Number_of_grids_vector(:))
00295 !
00296       igrid = search%msg_intersections%first_src_all_extents_grid_id
00297 !
00298 ! Can man die offset und partition information ausnutzen ?
00299 !
00300 !===> Allocate work vectors
00301 !
00302 ! boxes(i)     = Box around ith extra point with interior radius
00303 !                "dist_real (i)"
00304 ! send_mask(i) = Does the i-th extra point to be transferred 
00305 !                to the corresponding process ?
00306 !
00307       Allocate (boxes (2, ndim_3d, n_extra), STAT = ierror)
00308 
00309       if ( ierror > 0 ) then
00310          ierrp (1) = ierror
00311          ierrp (2) = n_extra * (2 * ndim_3d)
00312 
00313          ierror = PRISM_Error_Alloc
00314          call psmile_error ( ierror, 'boxes', &
00315                              ierrp, 2, __FILE__, __LINE__ )
00316          return
00317       endif
00318 !
00319       Allocate (send_mask (n_extra), STAT = ierror)
00320 
00321       if ( ierror > 0 ) then
00322          ierrp (1) = ierror
00323          ierrp (2) = n_extra
00324 
00325          ierror = PRISM_Error_Alloc
00326          call psmile_error ( ierror, 'send_mask', &
00327                              ierrp, 2, __FILE__, __LINE__ )
00328          return
00329       endif
00330 !
00331       mask_changed = .true.
00332 !
00333 !===> Compute range (bounding box) for global nearest neighbour
00334 !     search of extra points
00335 !
00336 !     ?dist_real = huge ? neighbors_3d (:, i, nb_extra) auswerten ?
00337 !     !!! TODO: Diese Punkte loesen eine Suche in allen Bloecken aus !
00338 !               Besser erst lokal in der Nachbarschaft suchen !
00339 !
00340 !==> Get maximal extension for 3rd direction (z-direction)
00341 !    ? einmal berechnen ?
00342 !
00343      real_huge = huge (dist_real(1,1))
00344      dist_max (1) = extents (1, vrt, igrid)
00345      dist_max (2) = extents (2, vrt, igrid)
00346 !
00347 #ifdef DEBUGX
00348      print *, "dist_max", dist_max
00349 #endif
00350 !
00351       do n = 1, n_total
00352         if (global_grid_id == comp_info%all_extent_infos(4,n)) then
00353            dist_max (1) = min (dist_max(1), extents(1, vrt, n))
00354            dist_max (2) = max (dist_max(2), extents(2, vrt, n))
00355         endif
00356       end do
00357 #ifdef DEBUGX
00358      print *, "dist_max", dist_max
00359 #endif
00360 !
00361       do ibeg = 1, n_extra, inlp_len
00362          iend = min (n_extra, ibeg + inlp_len - 1)
00363 !
00364 !        Construct boxes of interest in lon direction
00365 !        Delta lon = 2 * asin (sin (dist_real/(2*real_earth)) / cos (lat))
00366 !                    / real_deg2rad
00367 !cdir vector
00368          do i = ibeg, iend
00369             if (dist_real(i, nb_extra) * r_earth2 >= real_pih) then
00370                sin_d = 1.0
00371             else
00372                sin_d = abs(sin(dist_real(i, nb_extra) * r_earth2))
00373             endif
00374 
00375             cos_lat = cos (tgt_coords_y(indices(i)) * real_deg2rad)
00376 
00377             if (sin_d >= cos_lat) then
00378                delta = period2(lon)
00379             else
00380                delta = 2.0d0 * asin (sin_d / cos_lat) / real_deg2rad
00381                delta = min (period2(lon), delta)
00382             endif
00383 
00384             boxes (1, lon, i) = tgt_coords_x(indices(i)) - delta
00385             boxes (2, lon, i) = tgt_coords_x(indices(i)) + delta
00386          end do
00387 
00388 !cdir vector
00389          do i = ibeg, iend
00390             if (boxes (2,lon,i) - boxes (1,lon,i) > period2(lon)*2) then
00391                boxes (1,lon,i) = -period2(lon)
00392                boxes (2,lon,i) =  period2(lon)
00393             else if (boxes (1,lon,i) < -period2(lon)*2) then
00394                boxes (1,lon,i) = boxes (1,lon,i) + period2(lon)*2
00395                boxes (2,lon,i) = boxes (2,lon,i) + period2(lon)*2
00396             else if (boxes (2,lon,i) >  period2(lon)*2) then
00397                boxes (1,lon,i) = boxes (1,lon,i) - period2(lon)*2
00398                boxes (2,lon,i) = boxes (2,lon,i) - period2(lon)*2
00399             endif
00400          end do ! i
00401 
00402 !        Construct boxes of interest in lat direction
00403 !        Delta lat = dist_real / (real_earth * real_deg2rad)
00404 
00405 !cdir vector
00406          do i = ibeg, iend
00407             boxes (1, lat, i) = max (tgt_coords_y(indices(i)) -                        &
00408                                      min (period2(lat), dist_real(i, nb_extra)*r_lat), &
00409                                      real(common_grid_range(1,lat)))
00410             boxes (2, lat, i) = min (tgt_coords_y(indices(i)) +                        &
00411                                      min (period2(lat), dist_real(i, nb_extra)*r_lat), &
00412                                      real(common_grid_range(2,lat)))
00413          end do
00414       end do ! j
00415 !
00416       range_box (1, lon) = minval (boxes (1, lon, :))
00417       range_box (2, lon) = maxval (boxes (2, lon, :))
00418 !
00419       range_box (1, lat) = minval (boxes (1, lat, :))
00420       range_box (2, lat) = maxval (boxes (2, lat, :))
00421 !
00422 !        Construct boxes of interest in vertical direction
00423 !cdir vector
00424       do i = 1, n_extra
00425          if (dist_real(i, nb_extra) == real_huge) then
00426             boxes (1, vrt, i) = dist_max (1)
00427             boxes (2, vrt, i) = dist_max (2)
00428          else
00429             boxes (1, vrt, i) = tgt_coords_z(indices(i)) -             &
00430                               dist_real(i, nb_extra)
00431             boxes (2, vrt, i) = tgt_coords_z(indices(i)) +             &
00432                               dist_real(i, nb_extra)
00433 #ifdef DEBUGX
00434      print *, "dist_real", i, indices(i), dist_real(i, nb_extra)
00435 #endif
00436          endif
00437       end do
00438 !
00439       range_box (1, vrt) = minval (boxes (1, vrt, :))
00440       range_box (2, vrt) = maxval (boxes (2, vrt, :))
00441 !
00442 #ifdef PRISM_ASSERTION
00443       if (range_box (2,lon) - range_box (1,lon) > period2(lon)*4) then
00444           print *, 'range in lon direction', range_box (1:2,lon)
00445          call psmile_assert ( __FILE__, __LINE__, &
00446                              'range_box too large in lon direction')
00447       endif
00448 !
00449       if (range_box (2,lat) - range_box (1,lat) > period2(lat)*4) then
00450           print *, 'range in lat direction', range_box (1:2,lat)
00451          call psmile_assert ( __FILE__, __LINE__, &
00452                              'range_box too large in lat direction')
00453       endif
00454 #endif
00455 !
00456 !===> Transform range "range_box" into cyclic ranges
00457 !
00458       call psmile_transform_extent_cyclic (grid_type,           &
00459                   range_box, transformed, tr_codes, n_trans, ierror)
00460       if (ierror > 0) return
00461 !
00462 !     create lookup table for translating igrid into a icomp
00463 !
00464       Allocate (igrid_to_dest_comp(SUM(comp_info%Number_of_grids_vector)), stat = ierror)
00465 
00466       if ( ierror > 0 ) then
00467          ierrp (1) = ierror
00468          ierrp (2) = SUM(comp_info%Number_of_grids_vector)
00469 
00470          ierror = PRISM_Error_Alloc
00471          call psmile_error ( ierror, 'igrid_to_dest_comp', &
00472                              ierrp, 2, __FILE__, __LINE__ )
00473          return
00474       endif
00475 
00476       igrid = 0
00477       do dest_comp = 1, comp_info%size
00478          do j = 1, comp_info%Number_of_grids_vector(dest_comp)
00479             igrid = igrid + 1
00480             igrid_to_dest_comp(igrid) = dest_comp
00481          enddo
00482       enddo
00483 !
00484 !===> Control extents of other domains in order to find partner
00485 !
00486 ! igrid = current grid
00487 !
00488 !     loop over all grids/blocks (local and remote ones)
00489       do igrid = 1, SUM(comp_info%Number_of_grids_vector)
00490 
00491          dest_comp = igrid_to_dest_comp(igrid)
00492 
00493          if (mask_changed) then
00494             mask_changed  = .false.
00495             send_mask (:) = .false.
00496          endif
00497 !
00498 ! TODO:
00499 ! Das ist mir zu teuer; erst mit den extents in einer einfachen
00500 ! schleife potentiell partner finden; siehe found (:)
00501 ! in psmile_find_intersect
00502 !
00503 !        if current block is not part of the same global grid
00504          if (global_grid_id /= comp_info%all_extent_infos(4,igrid)) cycle
00505 !
00506 !===> ... Is this my info
00507 !         (note ranks start with 0, ...)
00508 !
00509          if (rank == dest_comp-1 .and. &
00510                comp_info%all_extent_infos(1,igrid) == grid_id) cycle
00511 !
00512 !===> ... Does the "n"-th grid and "range_box" coincide ?
00513 !        Rausziehen und vektorisieren ?
00514 !
00515 !  n_int = Number of significant intersections
00516 !
00517 !cdir vector
00518          do i = 1, n_trans
00519             dinter (1, :, i) = max (transformed(1,:,i), &
00520                                     extents(1,:,igrid))
00521             dinter (2, :, i) = min (transformed(2,:,i), &
00522                                     extents(2,:,igrid))
00523          end do
00524 !
00525          n_int = 0
00526 !cdir vector
00527          do i = 1, n_trans
00528             if (minval(dinter (2,:,i) - dinter (1,:,i)) >= 0.0d0) then
00529                n_int = n_int + 1
00530                found (n_int) = i
00531             endif
00532          end do
00533 !
00534          if (n_int == 0) cycle
00535 !
00536 !===> ... Transform intersections back into original range
00537 !
00538          do i = 1, n_int
00539             if (tr_codes(found(i)) /= code_no_trans) then
00540                call psmile_transform_extent_back (tr_codes(found(i)), &
00541                   dinter(:, :, found(i)), dinter_trans, 1, ierror)
00542                if ( ierror /= 0 ) return
00543 
00544                dinter (:, :, found(i)) = dinter_trans
00545             endif
00546          end do
00547 !
00548 !===> ... Get the extra points whose radius has an intersection
00549 !         with the extent of the "n"-th grid
00550 !
00551 ! send_mask(i) = Does the i-th extra point to be transferred 
00552 !                to the corresponding process ?
00553 !???  What about cyclic boundaries ????
00554 !???  use global offsets here !
00555 !
00556 ! Bedingung: 1. Punkt is in dinter drin
00557 !            2. vereinfachte distanz kleiner als dist_real
00558 !
00559          do i = 1, n_int
00560 #ifdef DEBUGX
00561 print *, 'extent controlled', i, n_int, dinter(:,:,found(i))
00562 #endif
00563 !cdir vector
00564             do j = 1, n_extra
00565                send_mask (j) = send_mask (j) .or. &
00566                      (boxes(2,lon,j) >= dinter(1,lon,found(i)) .and. &
00567                       boxes(1,lon,j) <= dinter(2,lon,found(i)) .and. &
00568                       boxes(2,lat,j) >= dinter(1,lat,found(i)) .and. &
00569                       boxes(1,lat,j) <= dinter(2,lat,found(i)) .and. &
00570                       boxes(2,vrt,j) >= dinter(1,vrt,found(i)) .and. &
00571                       boxes(1,vrt,j) <= dinter(2,vrt,found(i)))
00572 #ifdef DEBUGX
00573 print *, j, boxes(:,:,j)
00574 #endif
00575             end do ! j
00576          end do ! i
00577 !
00578 !===> ... Get number of points to be sent
00579 !
00580          n_send = COUNT(send_mask)
00581          if (n_send == 0) cycle
00582 !
00583          mask_changed = .true.
00584 !
00585 !===> ... A grid of process "dest_comp" is a potential partner
00586 !
00587          dest = comp_info%psmile_ranks(dest_comp)
00588 !
00589          n_recv_req = n_recv_req + 1
00590 !
00591 #ifdef VERBOSE
00592          print 9970, trim(ch_id), rank, dest_comp, dest, n_send
00593 
00594          call psmile_flushstd
00595 #endif /* VERBOSE */
00596 !
00597 !===> ... Allocate send buffers
00598 !
00599 !  cf. subroutine PSMILe_Store_faces_3d_reg_real
00600 !
00601 !  len_rtem = Number of pieces of information
00602 !             per point in Real buffer "rbuf"
00603 !
00604 !  Real vector buf (1:ndrbuf):
00605 !  buf (:) = Coordinates of the point to be searched
00606 !            ndim_3d data items
00607 !  buf (:) = Maximal distance
00608 !            1 data item
00609 !
00610 !  Integer buffer ibuf (1:ndibuf):
00611 !
00612 !  ibuf (:) = Index in indices/dist_real/send_mask
00613 !
00614 !        len_rtem = ndim_3d + nb_extra ! coords + alle distancen
00615          len_rtem = ndim_3d + 1        ! coords + groesste Distance
00616 !
00617          len_rbuf = n_send * len_rtem
00618          len_ibuf = n_send * len_item
00619 !
00620          if (len_rbuf > ndrbuf) then
00621             if (ndrbuf > 0) then
00622                Deallocate (buf)
00623             endif
00624 !
00625             ndrbuf = len_rbuf
00626             Allocate (buf(ndrbuf), STAT = ierror)
00627 
00628             if ( ierror > 0 ) then
00629                ierrp (1) = ierror
00630                ierrp (2) = ndrbuf
00631 
00632                ierror = PRISM_Error_Alloc
00633                call psmile_error ( ierror, 'buf', &
00634                                    ierrp, 2, __FILE__, __LINE__ )
00635                return
00636             endif
00637          endif
00638 !
00639          if (len_ibuf > ndibuf) then
00640             if (ndibuf > 0) then
00641                Deallocate (ibuf)
00642             endif
00643 !
00644             ndibuf = len_ibuf
00645             Allocate (ibuf(ndibuf), STAT = ierror)
00646 
00647             if ( ierror > 0 ) then
00648                ierrp (1) = ierror
00649                ierrp (2) = ndibuf
00650 
00651                ierror = PRISM_Error_Alloc
00652                call psmile_error ( ierror, 'ibuf', &
00653                                    ierrp, 2, __FILE__, __LINE__ )
00654                return
00655             endif
00656          endif
00657 !
00658 !===> Store data in send buffers
00659 !     ??? compact machen !?!?
00660 !         Mehrfache Zellen Info's in ibuf und corner volumen
00661 !         eliminieren ?
00662 !
00663 #ifdef USE_PACK
00664          ibuf (1:n_send*len_item:len_item) = &
00665             PACK ((/ (i, i=1,n_extra) /), send_mask)
00666 #else
00667          ipi = 0
00668 
00669 !cdir vector
00670          do i = 1, n_extra
00671             if (send_mask (i)) then
00672                ibuf (ipi+1) = i
00673                ipi = ipi + len_item
00674             endif
00675          end do
00676 #endif /* USE_PACK */
00677 !
00678 !===> ... store coordinates and distance a single vectors 
00679 !         (to be consistent with storage of PRISM external coordinates)
00680 !         ? ist das wiklich besser, als die per Punkt zu speichern.
00681 !           Grund fuer die Feldweise Speicherung ist, die
00682 !           moegliche Wiederverwendung von Routinen.
00683 !
00684 ! ? besser direkt cos_search, sin_search, z versenden ?
00685 ! Das waeren 5 satt 3 items;
00686 ! Neu rechnen schneller als senden ?
00687 !              buf (ip+1) = cos_search (i, 1)
00688 !              buf (ip+2) = cos_search (i, 2)
00689 !              buf (ip+3) = sin_search (i, 1)
00690 !              buf (ip+4) = sin_search (i, 2)
00691 !              buf (ip+5) = z_search (i) = tgt_coords_z (indices(i))
00692 !
00693 #ifdef ALL_ITEM_PER_POINT
00694          ip = 0
00695 !cdir vector
00696          do i = 1, n_extra
00697             if (send_mask (i)) then
00698 !
00699                buf (ip+1) = tgt_coords_x (indices(i))
00700                buf (ip+2) = tgt_coords_y (indices(i))
00701                buf (ip+3) = tgt_coords_z (indices(i))
00702 !
00703                buf (ip+4) = dist_real (i, nb_extra)
00704                ip = ip + len_rtem
00705             endif
00706          end do
00707 #else
00708          ip = 0
00709 !cdir vector
00710          do i = 1, n_extra
00711             if (send_mask (i)) then
00712                ip = ip + 1
00713                buf (ip           ) = tgt_coords_x (indices(i))
00714                buf (ip+ n_send   ) = tgt_coords_y (indices(i))
00715                buf (ip+(n_send*2)) = tgt_coords_z (indices(i))
00716                buf (ip+(n_send*3)) = dist_real (i, nb_extra)
00717             endif
00718          end do
00719 #endif
00720 !
00721 #ifdef TODO
00722 ! TODO: If dest_comp == rank, direct call of psmile_search_donor_extra()
00723          if (dest_comp == rank) then
00724 !
00725             search_global%sender = dest
00726             search_global%msg_extra = msg_extra (1:nd_msg)
00727 !     search_global%len_msg = nd_msg
00728 !
00729             call psmile_search_donor_extra (search_global, tol, ierror)
00730             if (ierror > 0) return
00731 
00732          endif
00733 #endif /* TODO */
00734 !
00735 !===> ... Send request to destination process
00736 !         extra_msg is received by routine PSMILe_Enddef_extra and
00737 !         the other buffer are received by routine
00738 !         PSMILe_Enddef_action_extra.
00739 !
00740 !  extra_msg (1)  = Type of request
00741 !  extra_msg (2)  = Datatype
00742 !  extra_msg (3)  = Length of buffer "ibuf" containing the integer data.
00743 !  extra_msg (4)  = Length of buffer  "buf" containing the
00744 !                   real/real data.
00745 !  extra_msg (5)  = Global comp id of component
00746 !  extra_msg (6)  = Global var id "id_trans_out"
00747 !  extra_msg (7)  = Grid Type of sending grid
00748 !                   (PRISM_Reglonlatvrt, ...)
00749 !  extra_msg (8)  = Number of control volumes sent
00750 !  extra_msg (9)  = Number of integer data items per control
00751 !                   volume sent
00752 !  extra_msg (10) = Number of real/real data items per control
00753 !                   volume sent
00754 !  extra_msg (11) = Is data on global offset available ?
00755 !  extra_msg (12) = I-Index of global offset (partition)
00756 !  extra_msg (13) = J-Index of global offset (partition)
00757 !  extra_msg (14) = K-Index of global offset (partition)
00758 !
00759 !  extra_msg (15) = Number of the request
00760 !  extra_msg (16) = num_neigh (Number of interpolation bases)
00761 !  extra_msg (17) = local grid id on message destination process
00762 !
00763          extra_msg (1)  = PSMILe_nnghbr3D
00764          extra_msg (2)  = PRISM_REAL
00765          extra_msg (3)  = len_ibuf
00766          extra_msg (4)  = len_rbuf
00767          extra_msg (5)  = comp_info%global_comp_id
00768          extra_msg (6)  = search%msg_intersections%transient_out_id
00769 !
00770          extra_msg (7)  = grid_type
00771          extra_msg (8)  = n_send
00772          extra_msg (9)  = len_item
00773          extra_msg (10) = len_rtem
00774 !
00775 !        ... No partition info
00776 !        Partition info senden; dann koennte man srcloc ausnutzen
00777 !
00778          extra_msg (11) = 0
00779 !
00780          extra_msg (15) = n_recv_req
00781          extra_msg (16) = nb_extra
00782 
00783          extra_msg (17) = comp_info%all_extent_infos(1,igrid)
00784 !
00785 #ifdef DEBUGX
00786       print *, 'extra_msg (1:4)', extra_msg (1:4)
00787          do i = 1, n_send
00788             print *, ibuf ((i-1)*len_item+1:i*len_item)
00789          end do
00790 #endif
00791 !
00792          call psmile_bsend (extra_msg, nd_msgextra, MPI_INTEGER, &
00793                             dest, exttag, comm_psmile, ierror)
00794          if (ierror /= MPI_SUCCESS) then
00795             ierrp (1) = ierror
00796             ierrp (2) = dest
00797             ierrp (3) = exttag
00798 
00799             ierror = PRISM_Error_Send
00800 
00801             call psmile_error (ierror, 'psmile_bsend(msg)', &
00802                                ierrp, 3, __FILE__, __LINE__ )
00803             return
00804          endif
00805 !
00806          call psmile_bsend (ibuf, len_ibuf, MPI_INTEGER, &
00807                             dest, exttag, comm_psmile, ierror)
00808          if (ierror /= MPI_SUCCESS) then
00809             ierrp (1) = ierror
00810             ierrp (2) = dest
00811             ierrp (3) = exttag
00812 
00813             ierror = PRISM_Error_Send
00814 
00815             call psmile_error (ierror, 'psmile_bsend(ibuf)', &
00816                                ierrp, 3, __FILE__, __LINE__ )
00817             return
00818          endif
00819 !
00820          call psmile_bsend (buf, len_rbuf, MPI_REAL, &
00821                             dest, exttag, comm_psmile, ierror)
00822          if (ierror /= MPI_SUCCESS) then
00823             ierrp (1) = ierror
00824             ierrp (2) = dest
00825             ierrp (3) = exttag
00826 
00827             ierror = PRISM_Error_Send
00828 
00829             call psmile_error (ierror, 'psmile_bsend(buf)', &
00830                                ierrp, 3, __FILE__, __LINE__ )
00831             return
00832          endif
00833 !
00834 !===> ... Setup request for answer of destination process
00835 !         ??? wirklich; sollte wohl von dem normalen abgehandelt werden
00836 !
00837          if (n_recv_req == 1) then
00838             call MPI_Irecv (answer, nd_msgextra, MPI_INTEGER, MPI_ANY_SOURCE, &
00839                             rexttag, comm_psmile, recv_req, ierror)
00840             if (ierror /= MPI_SUCCESS) then
00841 
00842                ierrp (1) = ierror
00843                ierrp (2) = dest
00844                ierrp (3) = rexttag
00845 
00846                ierror = PRISM_Error_Recv
00847 
00848                call psmile_error ( ierror, 'MPI_Irecv', &
00849                                    ierrp, 3, __FILE__, __LINE__ )
00850                return
00851 
00852             endif
00853          endif
00854 !
00855       end do ! igrid
00856 !
00857 !===> Deallocate
00858 !
00859       Deallocate (send_mask, boxes, igrid_to_dest_comp)
00860 !
00861       if (ndrbuf > 0) Deallocate (buf)
00862       if (ndibuf > 0) Deallocate (ibuf)
00863 !
00864 #ifdef __BUG__
00865       if (n_recv_req == 0) then
00866 
00867 !rr      send_info%nrecv and send_info%num2recv already may contain the results
00868 !rr      from the global search for filling the interpolation stencil. Here we
00869 !rr      perform the extra search for points for which no unmasked source points
00870 !rr      have been found. It must not be set to zero here as it is later used
00871 !rr      in psmile_compact_neighbours to compact points from the global search.
00872 !rr      send_info%nrecv and send_info%num2recv get updated in psmile_select_nn_found
00873 !rr      which is called from this routine.
00874 
00875          send_info%nrecv    = 0
00876          send_info%num2recv = 0
00877 
00878          go to 1000
00879       endif
00880 #endif
00881 
00882       if (n_recv_req == 0) go to 1000
00883 !
00884 !-------------------------------------------------------------------------
00885 !     Wait for answers
00886 !      Note: (2) Message from a partner with an intersection is disabled
00887 !                since request for grid receive (lrequest (3)) is setup
00888 !                if such a message is found.
00889 !            ??? Koennte man enablen wenn lrequest(3) == MPI_REQUEST_NULL
00890 !            (3) Old receive of grid data (paction%lrequest (3)) is disabled
00891 !-------------------------------------------------------------------------
00892 !
00893 ! nrecv      = Number of significant messages received
00894 !
00895       nrecv = 0
00896 !
00897       Allocate (sel_info (n_recv_req), stat = ierror)
00898       if ( ierror > 0 ) then
00899          ierrp (1) = ierror
00900          ierrp (2) = n_recv_req
00901 
00902          ierror = PRISM_Error_Alloc
00903          call psmile_error ( ierror, 'sel_info', ierrp, 2, &
00904                              __FILE__, __LINE__ )
00905          return
00906       endif
00907 !
00908 !===> Save old values of requests (2:3),
00909 !     ignore index 2 () and
00910 !     set index 3 to first receive of returned meta data
00911 !
00912       save_lreq (2:3) = paction%lrequest (2:3)
00913       paction%lrequest (2) = MPI_REQUEST_NULL
00914 !
00915       do n = 1, n_recv_req
00916          paction%lrequest (3) = recv_req
00917 !
00918          index = 0
00919          do while (index /= 3) 
00920 #ifdef DEBUG
00921             print *, trim(ch_id), paction%nreq, recv_req
00922             call psmile_flushstd
00923 #endif
00924 !
00925             call MPI_Waitany (paction%nreq, paction%lrequest, index, status, ierror)
00926 
00927             if ( ierror /= MPI_SUCCESS ) then
00928                ierrp (1) = ierror
00929                ierrp (2) = status (MPI_SOURCE)
00930                ierrp (3) = status (MPI_TAG)
00931 
00932                ierror = PRISM_Error_MPI
00933 
00934                call psmile_error ( ierror, 'MPI_Waitany', &
00935                                  ierrp, 3, __FILE__, __LINE__ )
00936                return
00937             endif
00938 
00939 #ifdef PRISM_ASSERTION
00940             if (index == MPI_UNDEFINED) then
00941                call psmile_assert ( __FILE__, __LINE__, &
00942                                     'request list is empty')
00943             endif
00944 #endif
00945 !
00946             if (index /= 3) then
00947                call psmile_enddef_action (search, index, status, ierror)
00948                if (ierror > 0) return
00949             endif
00950          end do ! while
00951 !
00952 !===> ... Get 
00953 !
00954          sender = status (MPI_SOURCE)
00955          len_ibuf = answer (3)
00956          len_rbuf = answer (4)
00957 !
00958 #ifdef VERBOSE
00959          print 9960, trim(ch_id), sender, len_ibuf, len_rbuf
00960 
00961          call psmile_flushstd
00962 #endif /* VERBOSE */
00963 !
00964 #ifdef PRISM_ASSERTION
00965          if (len_ibuf < 0) then
00966             print *, 'len_ibuf =', len_ibuf
00967             call psmile_assert (__FILE__, __LINE__, &
00968                  "len_ibuf should be >= 0")
00969          endif
00970 !
00971          if (len_rbuf < 0) then
00972             print *, 'len_rbuf =', len_rbuf
00973             call psmile_assert (__FILE__, __LINE__, &
00974                  "len_rbuf should be >= 0")
00975          endif
00976 #endif
00977 !
00978          if (len_ibuf > 0) then
00979             Allocate (ibuf (1:len_ibuf), stat = ierror)
00980 
00981             if ( ierror > 0 ) then
00982                ierrp (1) = ierror
00983                ierrp (2) = len_ibuf
00984 
00985                ierror = PRISM_Error_Alloc
00986                call psmile_error ( ierror, 'ibuf', ierrp, 2, &
00987                                    __FILE__, __LINE__ )
00988                return
00989             endif
00990 !
00991             call MPI_Recv (ibuf, len_ibuf, MPI_INTEGER, sender, &
00992                            rexttag, comm_psmile, status, ierror)
00993             if (ierror /= MPI_SUCCESS) then
00994 
00995                ierrp (1) = ierror
00996                ierrp (2) = sender
00997                ierrp (3) = rexttag
00998 
00999                ierror = PRISM_Error_Recv
01000 
01001                call psmile_error ( ierror, 'MPI_Recv(ibuf)', ierrp, 3, &
01002                                    __FILE__, __LINE__ )
01003                return
01004             endif
01005 !
01006             Allocate (buf (1:len_rbuf), stat = ierror)
01007 
01008             if ( ierror > 0 ) then
01009                ierrp (1) = ierror
01010                ierrp (2) = len_rbuf
01011 
01012                ierror = PRISM_Error_Alloc
01013                call psmile_error ( ierror, 'buf', ierrp, 2, &
01014                                    __FILE__, __LINE__ )
01015                return
01016             endif
01017 !
01018             call MPI_Recv (buf, len_rbuf, MPI_REAL, sender, &
01019                            rexttag, comm_psmile, status, ierror)
01020             if (ierror /= MPI_SUCCESS) then
01021 
01022                ierrp (1) = ierror
01023                ierrp (2) = sender
01024                ierrp (3) = rexttag
01025 
01026                ierror = PRISM_Error_Recv
01027 
01028                call psmile_error ( ierror, 'MPI_Recv(rbuf)', ierrp, 3, &
01029                                    __FILE__, __LINE__ )
01030                return
01031             endif
01032 !
01033 !===> ...
01034 !
01035 ! n_send  = Number of cells to be searched
01036 ! n_found = Number of interpolation bases found
01037 ! n_liste = Number of data items to be used for interpolation
01038 !           n_liste <= n_found since a data item can be used
01039 !           multiply for interpolation.
01040 !
01041             n_send  = answer (7)
01042             n_liste = answer (8)
01043             n_found = answer (9)
01044             ireq    = answer (15)
01045 !
01046 #ifdef PRISM_ASSERTION
01047             if (answer (1) /= PSMILe_nnghbr3D) then
01048                print *, 'answer(1)', answer(1), PSMILe_nnghbr3D
01049                call psmile_assert (__FILE__, __LINE__, &
01050                     "expected nearest neighbour interpolation")
01051             endif
01052 !
01053             if (ireq < 1 .or. ireq > n_recv_req) then
01054                print *, 'ireq, n_recv_req', ireq, n_recv_req
01055                call psmile_assert (__FILE__, __LINE__, &
01056                     "ireq must be in range of 1:n_recv_req")
01057             endif
01058 #endif
01059 !
01060             nrecv = nrecv + 1
01061 !
01062             sel_info(nrecv)%sender    = sender
01063             sel_info(nrecv)%n_liste   = n_liste
01064             sel_info(nrecv)%index     = answer (10)
01065             sel_info(nrecv)%method_id = answer (11)
01066             sel_info(nrecv)%msg_id    = answer (16)
01067 
01068             sel_info(nrecv)%real_buf => buf
01069 !
01070 !===> ... Allocate and initialize array "selected"
01071 !
01072 ! selected = Temporary vector for global nearest neighbour search
01073 !            for extra points with
01074 !            selected (1, *) = Number (index) of the receive
01075 !                              from which the nearest neigbour was
01076 !                              selected.
01077 !            selected (2, *) = Index in list of points 
01078 !                              (sent by neighbouring process)
01079 !            (cf. routine PSMILe_Add_nn_found_real)
01080 !            Dimension : selected (2, n_extra)
01081 !
01082 !
01083             if (.not. Allocated (selected)) then
01084                Allocate (selected(2, n_extra), stat = ierror)
01085 !
01086                if (ierror /= 0) then
01087                   ierrp (1) = n_extra * 2
01088 
01089                   ierror = PRISM_Error_Alloc
01090 
01091                   call psmile_error ( ierror, 'selected', ierrp, 1, &
01092                               __FILE__, __LINE__ )
01093                   return
01094                endif
01095 !
01096                selected (1, :) = 0
01097             endif
01098 !
01099 !===> ... Add information on points found by global search 
01100 !
01101             ip_dist = n_liste * ndim_3d
01102 !
01103             call psmile_add_nn_found_real (search, extra_search,     &
01104                         ibuf (1:n_send),                             &
01105                         ibuf   (n_send+1:2*n_send), n_send,          &
01106                         ibuf (2*n_send+1:2*n_send+n_found),          &
01107                         buf (ip_dist+1:ip_dist+n_found), n_found,    &
01108                         nb_extra, selected, sel_info, nrecv, ierror)
01109             if (ierror > 0) return
01110 !
01111             Deallocate (ibuf)
01112          endif
01113 !
01114 !===> ... Setup new request
01115 !
01116          if (n < n_recv_req) then
01117             call MPI_Irecv (answer, nd_msgextra, MPI_INTEGER, MPI_ANY_SOURCE, &
01118                               rexttag, comm_psmile, recv_req, &
01119                               ierror)
01120             if (ierror /= MPI_SUCCESS) then
01121 
01122                ierrp (1) = ierror
01123                ierrp (2) = dest
01124                ierrp (3) = rexttag
01125 
01126                ierror = PRISM_Error_Recv
01127 
01128                call psmile_error ( ierror, 'MPI_Irecv', &
01129                                     ierrp, 3, __FILE__, __LINE__ )
01130                return
01131             endif
01132          endif
01133       end do
01134 !
01135 !===> Determine which points are selected and return info to
01136 !     neighbouring processes
01137 !
01138       if (nrecv > 0) then
01139          call psmile_select_nn_found (search, extra_search,  &
01140                      send_info,                              &
01141                      selected, sel_info, nrecv, nb_extra,    &
01142                      neighbors_3d, nloc, num_neigh,          &
01143                      Grids(grid_id)%grid_shape, ierror)
01144          if (ierror > 0) return
01145       endif
01146 !
01147 !    ... Free memory
01148 !
01149       if (Allocated (selected)) then
01150          Deallocate (selected)
01151       endif
01152 !
01153       Deallocate (sel_info)
01154 !
01155 !    ... Restore original requests (2:3)
01156 !
01157 #ifdef PRISM_ASSERTION
01158       if (paction%lrequest (2) /= MPI_REQUEST_NULL .or. &
01159           paction%lrequest (3) /= MPI_REQUEST_NULL) then
01160          print *, 'request: ', paction%lrequest (2:3)
01161          call psmile_assert ( __FILE__, __LINE__, &
01162                              'Illegal request stored')
01163 
01164       endif
01165 #endif
01166 !
01167       paction%lrequest (2:3) = save_lreq (2:3)
01168 !
01169 !-------------------------------------------------------------------------
01170 !===> All done
01171 !-------------------------------------------------------------------------
01172 !
01173 1000  continue
01174 #ifdef VERBOSE
01175       print 9980, trim(ch_id), ierror
01176 
01177       call psmile_flushstd
01178 #endif /* VERBOSE */
01179 !
01180 !  Formats:
01181 !
01182 
01183 #ifdef VERBOSE
01184 
01185 9990 format (1x, a, ': psmile_global_search_nnx_real: var_id', i3, &
01186                     ' to ', i3, '(', i2, ')')
01187 9980 format (1x, a, ': psmile_global_search_nnx_real: eof ierror =', i3)
01188 9970 format (1x, a, ': psmile_global_search_nnx_real: send from', i3, &
01189                     ' to', i3, '[', i3, '], n_send =', i6)
01190 
01191 9960 format (1x, a, ': psmile_global_search_nnx_real: got rexttag message:', &
01192                     ' sender ', i4, ', len_ibuf, len_rbuf', 2i8)
01193 9950 format (1x, a, ': psmile_global_search_nnx_real: before waitany :', &
01194                     'nreq =', i4, ', recv_req ', i8)
01195 #endif /* VERBOSE */
01196 
01197 #ifdef DEBUG
01198 #endif
01199 
01200       end subroutine PSMILe_global_search_nnx_real

Generated on 18 Mar 2011 for Oasis4 by  doxygen 1.6.1