psmile_mg_srch_nneigh_irr_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 !
00008 ! !ROUTINE: PSMILe_MG_srch_nneigh_irr_real
00009 !
00010 subroutine psmile_mg_srch_nneigh_irr_real (grid_id,        &
00011                 arrays, search_mode, nref_3d,              &
00012                 sin_values, cos_values, grid_valid_shape,  &
00013                 z_coords, coords_shape,                    &
00014                 neighbors_3d, nloc, num_neigh,             &
00015                 sin_search, cos_search, z_search,          &
00016                 dist_real, dim1, indices, jbeg, jend,      &
00017                 mask_ind,                                  &
00018                 mask_array, mask_shape, mask_available,    &
00019                 tol, ierror)
00020 !
00021 ! !USES:
00022 !
00023   use PRISM_constants
00024 !
00025   use PSMILe, dummy_interface => PSMILe_MG_srch_nneigh_irr_real
00026 
00027   implicit none
00028 !
00029 ! !INPUT PARAMETERS:
00030 !
00031       Integer, Intent (In)            :: grid_id
00032 !
00033 !     Info on the component in which the donor cells
00034 !     should be searched.
00035 !
00036       Type (Extra_search_real)        :: arrays
00037 !
00038 !     Memory for metric information
00039 !
00040       Integer, Intent (In)            :: nref_3d
00041 !
00042 !     Something like the maximum number of neighbor to be searched for
00043 !
00044       Integer, Intent (In)            :: search_mode
00045 !
00046 !     Specifies the search mode for nearest neigbours with
00047 !        search_mode = 3 : Full 3d-search
00048 !        search_mode = 2 : Search in 2d-hyperplane (1st 2nd direction lon, lat)
00049 !        search_mode = 1 : Search in 1d-plane
00050 !
00051       Integer, Intent (In)            :: grid_valid_shape (2, ndim_3d)
00052 !
00053 !     Specifies the valid block shape for the "ndim_3d"-dimensional block
00054 
00055       Real, Intent (In)               :: 
00056          sin_values (grid_valid_shape(1,1):grid_valid_shape(2,1), 
00057                      grid_valid_shape(1,2):grid_valid_shape(2,2), 2)
00058 !
00059 !     Sin values of Longitudes and Latitudes (x_coords, y_coords)
00060 !
00061       Real, Intent (In)               :: 
00062          cos_values (grid_valid_shape(1,1):grid_valid_shape(2,1), 
00063                      grid_valid_shape(1,2):grid_valid_shape(2,2), 2)
00064 !    
00065 !     Cos values of Longitudes and Latitudes (x_coords, y_coords)
00066 !
00067       Integer, Intent (In)            :: coords_shape (2, ndim_3d)
00068 
00069 !     Dimension of coordinates (method) x_coords, ...
00070 
00071       Real, Intent (In)               :: z_coords(coords_shape(1,3): 
00072                                                   coords_shape(2,3))
00073 
00074       Integer, Intent (In)            :: nloc
00075 !
00076 !     Second dimension of neighbors array "neighbors_3d" and
00077 !     Total number of locations to be transferred
00078 !
00079       Integer, Intent (In)            :: num_neigh
00080 !
00081 !     Number of neighbors to be searched.
00082 !     Last dimension of neighbors array "neighbors_3d" and
00083 !     number of neighbors to be searched.
00084 !
00085       Integer,          Intent (In)   :: jbeg, jend
00086 !
00087 !     Shape of input arrays
00088 !
00089       Integer, Parameter              :: lat = 2
00090       Real, Intent (In)               :: sin_search (jbeg:jend, lat)
00091 !
00092 !     Sin values of the points for which the nearest neighbours
00093 !     should be searched.
00094 !
00095       Real, Intent (In)               :: cos_search (jbeg:jend, lat)
00096 !
00097 !     Cos values of the points for which the nearest neighbours
00098 !     should be searched.
00099 !
00100       Real, Intent (In)               :: z_search (jbeg:jend)
00101 !
00102 !     Z values of the points for which the nearest neighbours
00103 !     should be searched.
00104 !
00105       Integer, Intent (In)            :: dim1 (2)
00106 !
00107 !     Dimensions of "dist_real" in first direction 
00108 !
00109 ! Rene: without interface description declaration as indices(:)
00110 !       produces a segmentation fault. In this case it is
00111 !       necessary to define indices from jbeg to jend.
00112 !       This however violates assumptions for global search.
00113 !
00114       Integer, Intent (In)            :: indices (:)
00115 !
00116 !     Indices of the extra points in entire list of all points to be
00117 !     searched
00118 !
00119       Integer, Intent (In)            :: mask_shape (2, ndim_3d)
00120 !
00121 !     Dimension of (method) mask array
00122 !
00123       Logical, Intent (In)            :: 
00124          mask_array (mask_shape (1,1):mask_shape (2,1), 
00125                      mask_shape (1,2):mask_shape (2,2), 
00126                      mask_shape (1,3):mask_shape (2,3))
00127 !
00128 !     Mask of the method
00129 !
00130       Logical, Intent (In)             :: mask_available
00131 !
00132 !     Is mask specified in array "mask_array" ?
00133 !     mask_available = .false. : Mask is not available
00134 !                      .true.  : Mask is     available
00135 !
00136       Logical, Intent (In)             :: mask_ind(jbeg:jend)
00137 !
00138 !     Mask for j-indices already treated
00139 !
00140       Real, Intent (In)                :: tol
00141 !
00142 !     Some tolerance may be used later to evaluate distances
00143 !
00144 ! !INPUT/OUTPUT PARAMETERS:
00145 !
00146       Real, Intent (InOut)             :: dist_real (dim1(1):dim1(2), num_neigh)
00147 !
00148 !     Initial distances and final distances
00149 !
00150       Integer,           Intent (Out) :: neighbors_3d (ndim_3d, nloc, num_neigh)
00151 
00152 !     Indices of neighbor locations (interpolation bases)
00153 !     Index array for points that have been found
00154 !
00155 ! !OUTPUT PARAMETERS:
00156 !
00157      Integer, Intent (Out)           :: ierror
00158 
00159 !    Returns the error code of PSMILe_MG_srch_nneigh_irr_real;
00160 !            ierror = 0 : No error
00161 !            ierror > 0 : Severe error!
00162 !
00163 ! !DEFINED PARAMETERS:
00164 !
00165 !  real_earth = Earth radius in meter
00166 !
00167   Real, Parameter                 :: real_earth = 6400000.0
00168 !
00169   Real, Parameter                 :: acosp1 =  1.0
00170   Real, Parameter                 :: acosm1 = -1.0
00171 
00172   Integer, Parameter              :: lon = 1
00173 !
00174 ! !LOCAL VARIABLES
00175 !
00176   Real                            :: dist, dist1, distmax, val, fac, fac2
00177 
00178   Real                            :: sin_corner_lat(4,8)
00179   Real                            :: cos_corner_lat(4,8)
00180   Real                            :: sin_corner_lon(4,8)
00181   Real                            :: cos_corner_lon(4,8)
00182 
00183   Real                            :: sin_midp_lat(8)
00184   Real                            :: cos_midp_lat(8)
00185   Real                            :: sin_midp_lon(8)
00186   Real                            :: cos_midp_lon(8)
00187 
00188   Real                            :: distc (4)
00189 
00190   Real, Allocatable               :: distrad_c(:), radius_c(:)
00191   Real, Allocatable               :: distrad_f(:,:), radius_f(:,:)
00192 
00193   Logical, Allocatable            :: maskrad_c(:)
00194   Logical, Allocatable            :: maskrad_f(:,:)
00195 
00196   Integer, Allocatable            :: ijk0 (:,:)
00197   Integer                         :: ijk  (2,ndim_3d)
00198   Integer                         :: ii, jj, kk, nn
00199   Integer, Allocatable            :: next(:,:)
00200   Integer                         :: i, j, k, n
00201   Integer                         :: ifix, jfix, kfix
00202   Integer                         :: ncount
00203   Integer                         :: iloc(1)
00204 
00205   Type (Grid), Pointer            :: grid_info
00206   Type (Enddef_mg_real), Pointer :: my_arrays
00207 !
00208 !     ... multi-grid control
00209 !
00210   Integer                         :: level, nlev
00211   Integer, Allocatable            :: boxsize (:, :)
00212 !
00213 !     ... number of points in i, j, k directions
00214 !
00215   Integer                         :: len, leni, lenij, lenijk, lenj, lenk
00216   Integer                         :: leni_level, lenij_level
00217   Integer                         :: len_alloc
00218 !
00219 ! jind = loop index in compact vector "sin_search", "cos_search",
00220 !        "z_search" and "dist_real"
00221 !
00222 ! ind  = Corresponding index in "neighbors_3d"
00223 !
00224   Integer                         :: ind, jind
00225 !
00226 !     ... for error parameters
00227 !
00228   Integer, parameter              :: nerrp = 1
00229   Integer                         :: ierrp (nerrp)
00230 !
00231 ! !DESCRIPTION:
00232 !
00233 ! Subroutine "PSMILe_MG_srch_nneigh_irr_real" searches the next "num_neigh"
00234 ! nearest neighbours on the method-grid. num_neigh = 1 for the moment only.
00235 !
00236 ! TODO: Ausnutzen der einkommenden Info "neighbors_3d" ueber die Indices
00237 !       der schon gefundenen Punkte
00238 !
00239 ! !REVISION HISTORY:
00240 !
00241 !   Date      Programmer   Description
00242 ! ----------  ----------   -----------
00243 ! 05/02/01    R. Redler    created
00244 !
00245 !EOP
00246 !----------------------------------------------------------------------
00247 !
00248 #ifdef VERBOSE
00249   print 9990, trim(ch_id)
00250 
00251   call psmile_flushstd
00252 #endif /* VERBOSE */
00253 !
00254 !----------------------------------------------------------------------
00255 !  Initialization
00256 !----------------------------------------------------------------------
00257 !
00258   ierror = 0
00259 
00260   grid_info => Grids(grid_id)
00261 
00262   nlev = grid_info%nlev - 3
00263 
00264   leni   = grid_info%mg_infos(nlev)%levdim(1)+1
00265   lenj   = grid_info%mg_infos(nlev)%levdim(2)+1
00266   lenk   = grid_info%mg_infos(nlev)%levdim(3)+1
00267 
00268   lenij  = leni*lenj
00269   if ( search_mode == 3 ) then
00270      lenijk = lenij*lenk
00271   else
00272      lenijk = lenij
00273   endif
00274 !
00275 !----------------------------------------------------------------------
00276 !  Allocate memory
00277 !----------------------------------------------------------------------
00278 !
00279   allocate (maskrad_c(lenijk), stat = ierror)
00280   if (ierror /= 0) then
00281      ierrp (1) = lenijk
00282      ierror = PRISM_Error_Alloc
00283      call psmile_error ( ierror, 'maskrad_f', ierrp, 1, &
00284           __FILE__, __LINE__ )
00285      return
00286   endif
00287 
00288   allocate (distrad_c(lenijk), radius_c(lenijk), stat = ierror)
00289   if (ierror /= 0) then
00290      ierrp (1) = lenijk
00291      ierror = PRISM_Error_Alloc
00292      call psmile_error ( ierror, 'distrad_c, radius_c', ierrp, 1, &
00293           __FILE__, __LINE__ )
00294      return
00295   endif
00296 
00297   if ( search_mode == 2 ) then
00298       len_alloc = 64
00299   else
00300       len_alloc = 64*8
00301   endif
00302 
00303   allocate (maskrad_f(len_alloc,nlev), stat = ierror)
00304   if (ierror /= 0) then
00305      ierrp (1) = 2*ndim_3d*nlev
00306      ierror = PRISM_Error_Alloc
00307      call psmile_error ( ierror, 'maskrad_f', ierrp, 1, &
00308           __FILE__, __LINE__ )
00309      return
00310   endif
00311 
00312   allocate (distrad_f(len_alloc,nlev), radius_f(64,nlev), stat = ierror)
00313   if (ierror /= 0) then
00314      ierrp (1) = 6*2*ndim_3d*nlev
00315      ierror = PRISM_Error_Alloc
00316      call psmile_error ( ierror, 'distrad_f, radius_f', ierrp, 1, &
00317           __FILE__, __LINE__ )
00318      return
00319   endif
00320 
00321   allocate (boxsize(ndim_3d,nlev), ijk0(ndim_3d,nlev), stat = ierror)
00322   if (ierror /= 0) then
00323      ierrp (1) = 2*ndim_3d*nlev
00324      ierror = PRISM_Error_Alloc
00325      call psmile_error ( ierror, 'boxsize, ijk0', ierrp, 1, &
00326           __FILE__, __LINE__ )
00327      return
00328   endif
00329 
00330   allocate (next(ndim_3d,nlev), stat = ierror)
00331   if (ierror /= 0) then
00332      ierrp (1) = ndim_3d*nlev
00333      ierror = PRISM_Error_Alloc
00334      call psmile_error ( ierror, 'next', ierrp, 1, &
00335           __FILE__, __LINE__ )
00336      return
00337   endif
00338 
00339   ijk0(:,nlev) = grid_info%ijk0
00340 !
00341 ! compute coarsening factor to get from level "lev" onto the
00342 ! finest level "1". boxsize stores the number of data points
00343 ! in each direction in a particular box on a particular level.
00344 !
00345   boxsize (1:ndim_3d, 1) = 1
00346 
00347   do level = 2, nlev
00348      do i = 1, ndim_3d
00349         if ( grid_info%mg_infos(level  )%levdim(i) /= &
00350              grid_info%mg_infos(level-1)%levdim(i) ) then
00351            boxsize(i, level) = boxsize(i, level-1) * 2
00352         else
00353            boxsize(i, level) = boxsize(i, level-1)
00354         end if
00355      end do
00356   end do
00357 
00358   do jind = jbeg, jend
00359 
00360      if ( mask_ind(jind) ) then
00361         !
00362         ! Get number of points in i,j,k direction on the start level
00363         !
00364         leni   = grid_info%mg_infos(nlev)%levdim(1)+1
00365         lenj   = grid_info%mg_infos(nlev)%levdim(2)+1
00366         lenk   = grid_info%mg_infos(nlev)%levdim(3)+1
00367 
00368         lenij  = leni*lenj
00369         if ( search_mode == 3 ) then
00370            lenijk = lenij*lenk
00371         else
00372            lenijk = lenij
00373         endif
00374 
00375         maskrad_c = .true.
00376 
00377         ind = indices (jind)
00378 
00379         if ( search_mode == 2 ) then
00380            !
00381            ! Find nearest level in the vertical
00382            ! To do: Replace stupid search
00383            !
00384            dist = huge(dist)
00385            do k = grid_valid_shape(1,3), grid_valid_shape(2,3)
00386               val = abs( z_search (jind) - z_coords(k) )
00387               if ( val < dist ) then
00388                  val = dist
00389                  kfix = k
00390               endif
00391            enddo
00392         endif
00393 
00394         distmax = maxval (dist_real (jind, 1:num_neigh) )
00395         !
00396         ! distance from point to mid point of control volume on start level 
00397         ! Is this starting on level nlev too expensive (-> lenijk !)
00398         !
00399         fac = real_earth + z_search (jind)
00400 
00401         !cdir vector
00402         do n = 1, lenijk
00403            val = (  arrays%sin_cmidp_lat%vector(n) * sin_search(jind, lat)    &
00404                 +   arrays%cos_cmidp_lat%vector(n) * cos_search(jind, lat)    &
00405                 *  (arrays%cos_cmidp_lon%vector(n) * cos_search(jind, lon)    &
00406                 +   arrays%sin_cmidp_lon%vector(n) * sin_search(jind, lon)) )
00407 
00408            val = min (acosp1, val)
00409            val = max (acosm1, val)
00410 
00411            dist = fac * acos (val)
00412            distrad_c (n) = dist * dist
00413         enddo
00414 
00415         if ( search_mode == 3 ) then
00416            my_arrays => grid_info%mg_infos(nlev)%real_arrays
00417            n = 0
00418            do k = 1, lenk
00419               distrad_c (n+1:n+lenij) = distrad_c (n+1:n+lenij) + &
00420                    (my_arrays%midp(3)%vector(k)-z_search(jind))**2
00421               n = n + lenij
00422            enddo
00423         endif
00424 
00425         ! distance from point to sphere
00426         ! Note: This distance may be negative if point is inside the volume.
00427 
00428         distrad_c (1:lenijk) = sqrt (distrad_c(1:lenijk)) - arrays%radius(1:lenijk)
00429 
00430 200     continue ! entry point to proceed with other coarse level boxes
00431 
00432         ! reset pointers and values to fit coarse level.
00433 
00434         my_arrays => grid_info%mg_infos(nlev)%real_arrays
00435 
00436         next = 0
00437 
00438         leni   = grid_info%mg_infos(nlev)%levdim(1)+1
00439         lenj   = grid_info%mg_infos(nlev)%levdim(2)+1
00440         lenk   = grid_info%mg_infos(nlev)%levdim(3)+1
00441 
00442         lenij  = leni*lenj
00443         if ( search_mode == 3 ) then
00444            lenijk = lenij*lenk
00445         else
00446            lenijk = lenij
00447         endif
00448         !
00449         ! ignore control volumes that are farther away than what we have already
00450         !
00451         do i = 1, lenijk
00452            maskrad_c (i) = maskrad_c(i) .and. (distrad_c(i) < distmax)
00453         enddo
00454         !
00455         ! if we are already done take next target point
00456         !
00457         if ( count(maskrad_c) < 1 ) cycle
00458 
00459         ncount = 0
00460 
00461         do i = 1, lenijk
00462 
00463            if ( count(maskrad_c) < 1 ) exit
00464 
00465            iloc(:) = minloc (distrad_c(1:lenijk), maskrad_c(1:lenijk))
00466 #ifdef MINLOCFIX
00467            if (iloc(1).eq.0) iloc(1)=1
00468 #endif /* MINLOCFIX */
00469 
00470            kk = (iloc(1)                - 1) / lenij + 1
00471            jj = (iloc(1) - (kk-1)*lenij - 1) / leni  + 1
00472            ii =  iloc(1) - (kk-1)*lenij - (jj-1)*leni
00473 
00474            ijk(1,1) = ijk0(1,nlev) + (ii-1)*boxsize(1,nlev)
00475            ijk(1,2) = ijk0(2,nlev) + (jj-1)*boxsize(2,nlev)
00476 
00477            ijk(2,1) = min (grid_valid_shape(2,1), ijk(1,1)+boxsize(1,nlev)-1)
00478            ijk(2,2) = min (grid_valid_shape(2,2), ijk(1,2)+boxsize(2,nlev)-1)
00479 
00480            if ( search_mode == 2 ) then
00481               ijk(1,3) = kfix
00482               ijk(2,3) = kfix
00483            else
00484               ijk(1,3) = ijk0(3,nlev) + (kk-1)*boxsize(3,nlev)
00485               ijk(2,3) = min (grid_valid_shape(2,3), ijk(1,3)+boxsize(3,nlev)-1)
00486            endif
00487 
00488            ncount = count( mask_array(ijk(1,1):ijk(2,1), &
00489                                       ijk(1,2):ijk(2,2), &
00490                                       ijk(1,3):ijk(2,3)) )
00491            if ( ncount > 0 ) exit
00492 
00493            maskrad_c(iloc(1)) = .false. ! flag coarse cell as visited
00494 
00495         enddo
00496 
00497         if ( count(maskrad_c) < 1 ) cycle
00498 
00499         maskrad_c(iloc(1)) = .false.
00500 
00501         level = nlev
00502 
00503         maskrad_f = .true.
00504 
00505 100     continue ! start f-cycle
00506 
00507         ! sphere around the control volume for all but the start level
00508 
00509         if ( level < nlev ) then
00510            !
00511            !----------------------------------------------------------------------
00512            !       Prepare next level
00513            !----------------------------------------------------------------------
00514            !
00515            ! Offset of local range ijk  relative to the level 1 index
00516            !
00517            leni   = boxsize(1,level+1)/boxsize(1,level)
00518            lenj   = boxsize(2,level+1)/boxsize(2,level)
00519            lenk   = boxsize(3,level+1)/boxsize(3,level)
00520 
00521            lenij  = leni*lenj
00522            if ( search_mode == 3 ) then
00523               lenijk = lenij*lenk
00524            else
00525               lenijk = lenij
00526            endif
00527            !
00528            ! Offset for "level" in multigrid array
00529            ! next(:level) origin is (0,0,0)
00530            !
00531            next(1,level) = (next(1,level+1)+ii-1) * leni
00532            next(2,level) = (next(2,level+1)+jj-1) * lenj
00533            next(3,level) = (next(3,level+1)+kk-1) * lenk
00534            !
00535            ! Corresponding offset for full domain
00536            !
00537            ijk0(1,level) = next(1,level)
00538            ijk0(2,level) = next(2,level)
00539            ijk0(3,level) = next(3,level)
00540 
00541            do i = level-1, 1, -1
00542               ijk0(1,level) = ijk0(1,level)*boxsize(1,i+1)/boxsize(1,i)
00543               ijk0(2,level) = ijk0(2,level)*boxsize(2,i+1)/boxsize(2,i)
00544               ijk0(3,level) = ijk0(3,level)*boxsize(3,i+1)/boxsize(3,i)
00545            enddo
00546 
00547            ijk0(1,level) = ijk0(1,level) + ijk0(1,nlev)
00548            ijk0(2,level) = ijk0(2,level) + ijk0(2,nlev)
00549            ijk0(3,level) = ijk0(3,level) + ijk0(3,nlev)
00550            !
00551            ! Point to next finer level
00552            !
00553            my_arrays => grid_info%mg_infos(level)%real_arrays
00554 
00555            leni_level  = grid_info%mg_infos(level)%levdim(1)+1
00556            lenij_level = leni_level * (grid_info%mg_infos(level)%levdim(2)+1)
00557            !
00558            ! restrict lengths to stay within valid bounds at outer boxes
00559            !
00560            if ( next(1,level)+leni > grid_info%mg_infos(level)%levdim(1)+1 ) &
00561                 leni = grid_info%mg_infos(level)%levdim(1) + 1 - next(1,level)
00562 
00563            if ( next(2,level)+lenj > grid_info%mg_infos(level)%levdim(2)+1 ) &
00564                 lenj = grid_info%mg_infos(level)%levdim(2) + 1 - next(2,level)
00565 
00566            if ( next(3,level)+lenk > grid_info%mg_infos(level)%levdim(3)+1 ) &
00567                 lenk = grid_info%mg_infos(level)%levdim(3) + 1 - next(3,level)
00568 
00569            lenij  = leni*lenj
00570            if ( search_mode == 3 ) then
00571               lenijk = lenij*lenk
00572            else
00573               lenijk = lenij
00574            endif
00575            !
00576            ! collect the geographical data ...
00577            !
00578            do k = 1, lenk
00579               do j = 1, lenj
00580                  do i = 1, leni
00581 
00582                     n  = (k-1)*lenij + (j-1)*leni    + i
00583 
00584                     nn = (next(3,level) + k-1)*lenij_level + &
00585                          (next(2,level) + j-1)*leni_level  + &
00586                           next(1,level) + i
00587 
00588                     sin_corner_lon(1,n) = sin(my_arrays%chmin(lon)%vector(nn)*real_deg2rad)
00589                     cos_corner_lon(1,n) = cos(my_arrays%chmin(lon)%vector(nn)*real_deg2rad)
00590                     sin_corner_lat(1,n) = sin(my_arrays%chmin(lat)%vector(nn)*real_deg2rad)
00591                     cos_corner_lat(1,n) = cos(my_arrays%chmin(lat)%vector(nn)*real_deg2rad)
00592 
00593                     sin_corner_lon(2,n) = sin(my_arrays%chmax(lon)%vector(nn)*real_deg2rad)
00594                     cos_corner_lon(2,n) = cos(my_arrays%chmax(lon)%vector(nn)*real_deg2rad)
00595                     sin_corner_lat(2,n) = sin(my_arrays%chmin(lat)%vector(nn)*real_deg2rad)
00596                     cos_corner_lat(2,n) = cos(my_arrays%chmin(lat)%vector(nn)*real_deg2rad)
00597 
00598                     sin_corner_lon(3,n) = sin(my_arrays%chmax(lon)%vector(nn)*real_deg2rad)
00599                     cos_corner_lon(3,n) = cos(my_arrays%chmax(lon)%vector(nn)*real_deg2rad)
00600                     sin_corner_lat(3,n) = sin(my_arrays%chmax(lat)%vector(nn)*real_deg2rad)
00601                     cos_corner_lat(3,n) = cos(my_arrays%chmax(lat)%vector(nn)*real_deg2rad)
00602 
00603                     sin_corner_lon(4,n) = sin(my_arrays%chmin(lon)%vector(nn)*real_deg2rad)
00604                     cos_corner_lon(4,n) = cos(my_arrays%chmin(lon)%vector(nn)*real_deg2rad)
00605                     sin_corner_lat(4,n) = sin(my_arrays%chmax(lat)%vector(nn)*real_deg2rad)
00606                     cos_corner_lat(4,n) = cos(my_arrays%chmax(lat)%vector(nn)*real_deg2rad)
00607 
00608                     sin_midp_lon(n) = sin(my_arrays%midp(1)%vector(nn)*real_deg2rad)
00609                     cos_midp_lon(n) = cos(my_arrays%midp(1)%vector(nn)*real_deg2rad)
00610                     sin_midp_lat(n) = sin(my_arrays%midp(2)%vector(nn)*real_deg2rad)
00611                     cos_midp_lat(n) = cos(my_arrays%midp(2)%vector(nn)*real_deg2rad)
00612 
00613                  enddo
00614               enddo
00615            enddo
00616            !
00617            ! ... and calculate new distances
00618            !
00619            dist1 = 0.0
00620 
00621            do k = 1, lenk
00622               fac2 = real_earth + my_arrays%midp(3)%vector(k)
00623 
00624               if ( search_mode == 3 ) then
00625                  dist1 = max ( (my_arrays%midp (3)%vector(k) -     &
00626                                 my_arrays%chmin(3)%vector(k))**2,  &
00627                                (my_arrays%midp (3)%vector(k) -     &
00628                                 my_arrays%chmax(3)%vector(k))**2)
00629               endif
00630               !cdir vector
00631               do n = (k-1)*lenij+1, k*lenij
00632 
00633                  do nn = 1, 4
00634                     val = ( sin_corner_lat(nn,n) * sin_midp_lat(n)   &
00635                          +  cos_corner_lat(nn,n) * cos_midp_lat(n)   &
00636                          * (cos_corner_lon(nn,n) * cos_midp_lon(n)   &
00637                          +  sin_corner_lon(nn,n) * sin_midp_lon(n)) )
00638 
00639                     val = min (acosp1, val)
00640                     val = max (acosm1, val)
00641 
00642                     dist = fac2 * acos (val)
00643 
00644                     distc (nn) = sqrt(dist*dist + dist1)
00645                  enddo
00646 
00647                  radius_f(n,level) = maxval (distc)
00648               enddo
00649 
00650            enddo
00651 
00652            ! distance from point to mid point of control volume
00653            !  for all but the start level
00654 
00655            !cdir vector
00656            do n = 1, lenijk
00657               val = ( sin_midp_lat(n) * sin_search(jind,lat)   &
00658                    +  cos_midp_lat(n) * cos_search(jind,lat)   &
00659                    * (cos_midp_lon(n) * cos_search(jind,lon)   &
00660                    +  sin_midp_lon(n) * sin_search(jind,lon)) )
00661 
00662               val = min (acosp1, val)
00663               val = max (acosm1, val)
00664 
00665               dist = fac * acos (val)
00666               distrad_f(n,level) = dist * dist
00667            enddo
00668 
00669            if ( search_mode == 3 ) then
00670               n = 0
00671               do k = 1, lenk
00672                  distrad_f(n+1:n+lenij,level) = distrad_f (n+1:n+lenij,level) + &
00673                       (my_arrays%midp(3)%vector(k)-z_search(jind))**2
00674                  n = n + lenij
00675               end do
00676            endif
00677 
00678            distrad_f (1:lenijk,level) = sqrt (distrad_f(1:lenijk,level))
00679 
00680            ! distance from point to be searched for to sphere
00681 
00682            distrad_f(1:lenijk,level) = distrad_f(1:lenijk,level) - radius_f(1:lenijk,level)
00683 
00684            ! ignore control volumes that are farther away than what we have already
00685 
00686            do i = 1, lenijk
00687               maskrad_f(i,level) = maskrad_f(i,level) .and. (distrad_f(i,level) <= distmax)
00688            enddo
00689 
00690            ! go up one level and find another iloc there
00691 
00692            if ( count(maskrad_f(1:lenijk,level)) < 1 )  then
00693 
00694 500            continue
00695 
00696                ! no more boxes to check, reset current mask and distance and go up
00697 
00698                maskrad_f(:,level) = .true.
00699                distrad_f(:,level) = huge(dist)
00700 
00701                level = level + 1
00702 
00703                if ( level+1 > nlev ) go to 200
00704 
00705                leni   = boxsize(1,level+1)/boxsize(1,level)
00706                lenj   = boxsize(2,level+1)/boxsize(2,level)
00707                lenk   = boxsize(3,level+1)/boxsize(3,level)
00708 
00709                lenij  = leni*lenj
00710                if ( search_mode == 3 ) then
00711                   lenijk = lenij*lenk
00712                else
00713                   lenijk = lenij
00714                endif
00715 
00716                if ( count(maskrad_f(1:lenijk,level)) < 1 ) go to 500
00717 
00718                iloc(:) = minloc (distrad_f(1:lenijk,level), maskrad_f(1:lenijk,level))
00719 #ifdef MINLOCFIX
00720                if (iloc(1).eq.0) iloc(1)=1
00721 #endif /* MINLOCFIX */
00722                kk = (iloc(1)                - 1) / lenij + 1
00723                jj = (iloc(1) - (kk-1)*lenij - 1) / leni  + 1
00724                ii =  iloc(1) - (kk-1)*lenij - (jj-1) * leni
00725 
00726                go to 100
00727 
00728            else
00729 
00730               iloc(:) = minloc (distrad_f(1:lenijk,level), maskrad_f(1:lenijk,level))
00731 #ifdef MINLOCFIX
00732               if (iloc(1).eq.0) iloc(1)=1
00733 #endif /* MINLOCFIX */
00734            endif
00735 
00736            maskrad_f(iloc(1),level) = .false.
00737 
00738         endif ! (level < nlev)
00739 
00740 300     continue
00741         !
00742         !-------------------------------------------------------------------------
00743         !    Ignore points masked out
00744         !-------------------------------------------------------------------------
00745         !
00746         if ( mask_available .and. iloc(1) > 0 ) then
00747 
00748            ! check whether we have valid points in this volume
00749 
00750            do i = 1, lenijk
00751 
00752               kk = (iloc(1)                - 1) / lenij + 1
00753               jj = (iloc(1) - (kk-1)*lenij - 1) / leni  + 1
00754               ii =  iloc(1) - (kk-1)*lenij - (jj-1)*leni
00755 
00756               ijk(1,1) = min (ijk0(1,level) + (ii-1)*boxsize(1,level), grid_valid_shape(2,1))
00757               ijk(1,2) = min (ijk0(2,level) + (jj-1)*boxsize(2,level), grid_valid_shape(2,2))
00758 
00759               ijk(2,1) = min (grid_valid_shape(2,1), ijk(1,1)+boxsize(1,level)-1)
00760               ijk(2,2) = min (grid_valid_shape(2,2), ijk(1,2)+boxsize(2,level)-1)
00761 
00762               if ( search_mode == 2 ) then
00763                  ijk(1,3) = kfix
00764                  ijk(2,3) = kfix
00765               else
00766                  ijk(1,3) = min (ijk0(3,level) + (kk-1)*boxsize(3,level), grid_valid_shape(2,3))
00767                  ijk(2,3) = min (grid_valid_shape(2,3), ijk(1,3)+boxsize(3,level)-1)
00768               endif
00769 
00770               ncount = count( mask_array(ijk(1,1):ijk(2,1), &
00771                                          ijk(1,2):ijk(2,2), &
00772                                          ijk(1,3):ijk(2,3)) )
00773               if ( ncount > 0 ) exit
00774 
00775               ! reject control volume without any valid points
00776 
00777               maskrad_f(iloc(1),level) = .false.
00778 
00779               if ( count(maskrad_f(1:lenijk,level)) > 0 ) then
00780                    iloc(:) = minloc (distrad_f(1:lenijk,level), maskrad_f(1:lenijk,level))
00781               else
00782                    iloc(1) = 0
00783                    exit
00784               endif
00785 
00786            enddo
00787            !
00788            ! ------------------------------------------------------------------------
00789            ! Special case if only one valid point is left over in the current volume.
00790            ! ------------------------------------------------------------------------
00791            !
00792            if ( ncount == 1 ) then
00793 
00794               do k = ijk(1,3),ijk(2,3)
00795                  do j = ijk(1,2),ijk(2,2)
00796                     do i = ijk(1,1),ijk(2,1)
00797                        if ( mask_array(i,j,k) ) then
00798                           ifix = i
00799                           jfix = j
00800                           kfix = k
00801                        endif
00802                     enddo
00803                  enddo
00804               enddo
00805               !
00806               !  Compute distance of point "neighbors_3d (:, ind, 1)"
00807               !
00808               val = ( sin_values(ifix, jfix, lat) * sin_search(jind, lat)    &
00809                    +  cos_values(ifix, jfix, lat) * cos_search(jind, lat)    &
00810                    * (cos_values(ifix, jfix, lon) * cos_search(jind, lon)    &
00811                    +  sin_values(ifix, jfix, lon) * sin_search(jind, lon)) )
00812 
00813               val = min (acosp1, val)
00814               val = max (acosm1, val)
00815 
00816               dist = fac * acos (val)
00817 
00818               if ( search_mode == 2 ) then
00819                  dist = dist*dist
00820               else
00821                  dist = dist*dist + ( z_search (jind)-z_coords(k) )**2
00822               endif
00823 
00824               !  Wrong for num_neigh > 1 !
00825               !  We need to keep old values which have
00826               !  been found already in this case.
00827 
00828               if ( sqrt ( dist ) < distmax ) then
00829 
00830                  neighbors_3d (1, ind, 1) = ifix
00831                  neighbors_3d (2, ind, 1) = jfix
00832                  neighbors_3d (3, ind, 1) = kfix
00833 
00834                  distmax =  sqrt ( dist )
00835                  dist_real(jind,1) = distmax
00836 
00837               endif
00838 
00839               maskrad_f(iloc(1),level) = .false.
00840 
00841 !             iloc(1) = 0
00842 
00843 700           continue
00844 
00845               maskrad_f(:,level) = .true.
00846               distrad_f(:,level) = huge(dist)
00847 
00848               level = level + 1
00849 
00850               if ( level+1 > nlev ) go to 200
00851 
00852               leni   = boxsize(1,level+1)/boxsize(1,level)
00853               lenj   = boxsize(2,level+1)/boxsize(2,level)
00854               lenk   = boxsize(3,level+1)/boxsize(3,level)
00855 
00856               lenij  = leni*lenj
00857               if ( search_mode == 3 ) then
00858                  lenijk = lenij*lenk
00859               else
00860                  lenijk = lenij
00861               endif
00862 
00863               do i = 1, lenijk
00864                  maskrad_f(i,level) = maskrad_f(i,level) .and. (distrad_f(i,level) <= distmax)
00865               enddo
00866 
00867               if ( count(maskrad_f(1:lenijk,level)) < 1 ) go to 700
00868 
00869               iloc(:) = minloc (distrad_f(1:lenijk,level), maskrad_f(1:lenijk,level))
00870 #ifdef MINLOCFIX
00871               if (iloc(1).eq.0) iloc(1)=1
00872 #endif /* MINLOCFIX */
00873               kk = (iloc(1)                - 1) / lenij + 1
00874               jj = (iloc(1) - (kk-1)*lenij - 1) / leni  + 1
00875               ii =  iloc(1) - (kk-1)*lenij - (jj-1) * leni
00876 
00877               go to 300
00878 
00879            endif ! ncount == 1
00880 
00881         endif ! mask_available .and. iloc(1) > 0
00882 
00883         if ( iloc(1) > 0 ) then
00884             maskrad_f(iloc(1),level) = .false.
00885         else
00886 
00887 800        continue
00888 
00889            maskrad_f(:,level) = .true.
00890            distrad_f(:,level) = huge(dist)
00891 
00892            level = level + 1
00893 
00894            if ( level+1 > nlev ) go to 200
00895 
00896            leni   = boxsize(1,level+1)/boxsize(1,level)
00897            lenj   = boxsize(2,level+1)/boxsize(2,level)
00898            lenk   = boxsize(3,level+1)/boxsize(3,level)
00899 
00900            lenij  = leni*lenj
00901            if ( search_mode == 3 ) then
00902               lenijk = lenij*lenk
00903            else
00904               lenijk = lenij
00905            endif
00906 
00907            do i = 1, lenijk
00908               maskrad_f(i,level) = maskrad_f(i,level) .and. (distrad_f(i,level) <= distmax)
00909            enddo
00910 
00911            if ( count(maskrad_f(1:lenijk,level)) < 1 ) go to 800
00912 
00913            iloc(:) = minloc (distrad_f(1:lenijk,level), maskrad_f(1:lenijk,level))
00914 #ifdef MINLOCFIX
00915            if (iloc(1).eq.0) iloc(1)=1
00916 #endif /* MINLOCFIX */
00917            kk = (iloc(1)                - 1) / lenij + 1
00918            jj = (iloc(1) - (kk-1)*lenij - 1) / leni  + 1
00919            ii =  iloc(1) - (kk-1)*lenij - (jj-1) * leni
00920 
00921            go to 300
00922 
00923         endif
00924 
00925         level = level - 1
00926 
00927         if ( level == 3 ) go to 400 ! leave f-cycle and go to finest level 1
00928 
00929         go to 100 ! continue f-cycle
00930 
00931 400     continue
00932         !
00933         ! ------------------------------------------------------------------
00934         ! go over all points of the final selected control volume on level 3
00935         ! and find the nearest points.
00936         ! ------------------------------------------------------------------
00937         !
00938         if ( iloc(1) > 0 ) then
00939 
00940            leni   = ijk(2,1) - ijk(1,1) + 1
00941            lenj   = ijk(2,2) - ijk(1,2) + 1
00942            lenk   = ijk(2,3) - ijk(1,3) + 1
00943 
00944            lenij  = leni*lenj
00945            lenijk = lenij*lenk
00946 
00947            ! Compute distance from point to potential neighbours
00948 
00949            do k = ijk(1,3), ijk(2,3)
00950               do j = ijk(1,2), ijk(2,2)
00951                  do i = ijk(1,1), ijk(2,1)
00952 
00953                     n  = (k-ijk(1,3))*lenij + (j-ijk(1,2))*leni + i-ijk(1,1)+1
00954 
00955                     val = ( sin_values(i, j, lat) * sin_search(jind, lat)    &
00956                          +  cos_values(i, j, lat) * cos_search(jind, lat)    &
00957                          * (cos_values(i, j, lon) * cos_search(jind, lon)    &
00958                          +  sin_values(i, j, lon) * sin_search(jind, lon)) )
00959 
00960                     val = min (acosp1, val)
00961                     val = max (acosm1, val)
00962 
00963                     dist = fac * acos (val)
00964 
00965                     distrad_f(n,level) = dist*dist
00966 
00967                  end do
00968               end do
00969            end do
00970 
00971            if ( search_mode == 3 ) then
00972               n = 0
00973               do k = 1, lenk
00974                  distrad_f(n+1:n+lenij,level) = distrad_f(n+1:n+lenij,level) + &
00975                        ( z_search (jind)-z_coords(k) )**2
00976                  n = n + lenij
00977               end do
00978            endif
00979 
00980            distrad_f (1:lenijk,level) = sqrt (distrad_f(1:lenijk,level))
00981 
00982            ! ignore invalid points
00983 
00984            if ( mask_available ) then
00985 
00986               n = 0
00987               do k = ijk(1,3), ijk(2,3)
00988                  do j = ijk(1,2), ijk(2,2)
00989                     do i = ijk(1,1), ijk(2,1)
00990                        n = n+1
00991                        maskrad_f(n,level) = mask_array(i,j,k)
00992                     enddo
00993                  enddo
00994               enddo
00995 
00996               do i = 1, lenijk
00997                  maskrad_f(i,level) = maskrad_f(i,level) .and. (distrad_f(i,level) <= distmax)
00998               enddo
00999 
01000               ncount = count(maskrad_f(1:lenijk,level))
01001               len = min(num_neigh,ncount)
01002 
01003            else
01004 
01005               do i = 1, lenijk
01006                  maskrad_f(i,level) = distrad_f(i,level) <= distmax
01007               enddo
01008 
01009               len = min(num_neigh, lenijk)
01010 
01011            endif
01012            !
01013            ! Find the remaining num_neigh nearest neighbours
01014            ! in this final level 3 control volume. 
01015            !
01016            do n = 1, len
01017 
01018               do nn = 1, lenijk
01019 
01020                  iloc(:) = minloc(distrad_f(1:lenijk,level), maskrad_f(1:lenijk,level))
01021 #ifdef MINLOCFIX
01022                  if (iloc(1).eq.0) iloc(1)=1
01023 #endif /* MINLOCFIX */
01024                  kk = (iloc(1)                - 1) / lenij + 1
01025                  jj = (iloc(1) - (kk-1)*lenij - 1) / leni  + 1
01026                  ii =  iloc(1) - (kk-1)*lenij - (jj-1) * leni
01027 
01028                  i = max(grid_valid_shape(1,1),ijk(1,1)+ii-1)
01029                  j = max(grid_valid_shape(1,2),ijk(1,2)+jj-1)
01030 
01031                  if ( search_mode == 2 ) then
01032                     k = kfix
01033                  else
01034                     k = max(grid_valid_shape(1,3),ijk(1,3)+kk-1)
01035                  endif
01036 
01037                  neighbors_3d (1, ind, n) = i
01038                  neighbors_3d (2, ind, n) = j
01039                  neighbors_3d (3, ind, n) = k
01040 
01041                  distmax = distrad_f(iloc(1),level)
01042                  dist_real (jind, n) = distmax
01043 
01044                  maskrad_f(iloc(1),level) = .false.
01045                  exit ! lopp nn and go for next neighbour
01046 
01047               enddo ! nn
01048 
01049            enddo ! n
01050 
01051            ! reset current mask and distance and go up to level 4
01052 
01053 600        continue
01054 
01055            maskrad_f(:,level) = .true.
01056            distrad_f(:,level) = huge(dist)
01057 
01058            level = level + 1
01059 
01060            if ( level+1 > nlev ) go to 200
01061 
01062            leni   = boxsize(1,level+1)/boxsize(1,level)
01063            lenj   = boxsize(2,level+1)/boxsize(2,level)
01064            lenk   = boxsize(3,level+1)/boxsize(3,level)
01065 
01066            lenij  = leni*lenj
01067            if ( search_mode == 3 ) then
01068               lenijk = lenij*lenk
01069            else
01070               lenijk = lenij
01071            endif
01072 
01073            do i = 1, lenijk
01074               maskrad_f(i,level) = maskrad_f(i,level) .and. (distrad_f(i,level) <= distmax)
01075            enddo
01076 
01077            if ( count(maskrad_f(1:lenijk,level)) < 1 ) go to 600
01078 
01079            iloc(:) = minloc (distrad_f(1:lenijk,level), maskrad_f(1:lenijk,level))
01080 #ifdef MINLOCFIX
01081            if (iloc(1).eq.0) iloc(1)=1
01082 #endif /* MINLOCFIX */
01083            kk = (iloc(1)                - 1) / lenij + 1
01084            jj = (iloc(1) - (kk-1)*lenij - 1) / leni  + 1
01085            ii =  iloc(1) - (kk-1)*lenij - (jj-1) * leni
01086 
01087            go to 300
01088 
01089         endif
01090 
01091      endif ! mask_ind
01092 
01093   enddo ! jind
01094   !
01095   !===> All done
01096   !
01097   if (mask_available) then
01098      Deallocate (boxsize)
01099   endif
01100 
01101 #ifdef VERBOSE
01102   print 9980, trim(ch_id), ierror
01103 
01104   call psmile_flushstd
01105 #endif /* VERBOSE */
01106   !
01107   !  Formats:
01108   !
01109 9990 format (1x, a, ': psmile_mg_srch_nneigh_irr_real')
01110 9980 format (1x, a, ': psmile_mg_srch_nneigh_irr_real: eof, ierror =', i3)
01111 
01112 end subroutine PSMILe_MG_srch_nneigh_irr_real

Generated on 18 Mar 2011 for Oasis4 by  doxygen 1.6.1