00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 subroutine psmile_neigh_nearestx_3d_dble ( &
00012 grid_id, &
00013 coords1, coords2, coords3, &
00014 x_coords, y_coords, z_coords, &
00015 coords_shape, &
00016 mask_array, mask_shape, mask_available, &
00017 sin_values, cos_values, &
00018 grid_valid_shape, &
00019 srcloc, nloc, nprev, nsearch, &
00020 neighbors_3d, num_neigh, &
00021 extra_search, ierror)
00022
00023
00024
00025 use PRISM_constants
00026
00027 use PSMILe, dummy_interface => PSMILe_Neigh_nearestx_3d_dble
00028
00029 implicit none
00030
00031
00032
00033 Integer, Intent (In) :: grid_id
00034
00035
00036
00037
00038 Integer, Intent (In) :: nloc
00039
00040
00041
00042 Integer, Intent (In) :: nprev
00043
00044
00045
00046 Integer, Intent (In) :: nsearch
00047
00048
00049
00050
00051 Integer, Intent (In) :: srcloc (ndim_3d, nloc)
00052
00053
00054
00055
00056
00057
00058 Double Precision, Intent (In) :: coords1 (nloc)
00059 Double Precision, Intent (In) :: coords2 (nloc)
00060 Double Precision, Intent (In) :: coords3 (nloc)
00061
00062
00063
00064 Integer, Intent (In) :: coords_shape (2, ndim_3d)
00065
00066
00067
00068 Double Precision, Intent (In) :: x_coords(coords_shape(1,1):
00069 coords_shape(2,1),
00070 coords_shape(1,2):
00071 coords_shape(2,2),
00072 coords_shape(1,3):
00073 coords_shape(2,3))
00074 Double Precision, Intent (In) :: y_coords(coords_shape(1,1):
00075 coords_shape(2,1),
00076 coords_shape(1,2):
00077 coords_shape(2,2),
00078 coords_shape(1,3):
00079 coords_shape(2,3))
00080 Double Precision, Intent (In) :: z_coords(coords_shape(1,1):
00081 coords_shape(2,1),
00082 coords_shape(1,2):
00083 coords_shape(2,2),
00084 coords_shape(1,3):
00085 coords_shape(2,3))
00086
00087
00088
00089 Integer, Intent (In) :: mask_shape (2, ndim_3d)
00090
00091
00092
00093 Logical, Intent (In) :: mask_array (mask_shape (1,1):
00094 mask_shape (2,1),
00095 mask_shape (1,2):
00096 mask_shape (2,2),
00097 mask_shape (1,3):
00098 mask_shape (2,3))
00099
00100
00101 Logical, Intent (In) :: mask_available
00102
00103
00104
00105
00106
00107 Integer, Intent (In) :: grid_valid_shape (2, ndim_3d)
00108
00109
00110
00111 Double Precision, Intent (In) :: sin_values (grid_valid_shape(1,1):
00112 grid_valid_shape(2,1),
00113 grid_valid_shape(1,2):
00114 grid_valid_shape(2,2),
00115 grid_valid_shape(1,3):
00116 grid_valid_shape(2,3),
00117 2)
00118
00119
00120
00121 Double Precision, Intent (In) :: cos_values (grid_valid_shape(1,1):
00122 grid_valid_shape(2,1),
00123 grid_valid_shape(1,2):
00124 grid_valid_shape(2,2),
00125 grid_valid_shape(1,3):
00126 grid_valid_shape(2,3),
00127 2)
00128
00129
00130
00131
00132 Integer, Intent (In) :: num_neigh
00133
00134
00135
00136
00137
00138
00139 Type (Extra_search_info) :: extra_search
00140
00141
00142
00143
00144
00145
00146 Integer, Intent (Out) :: neighbors_3d (ndim_3d, nloc, num_neigh)
00147
00148
00149
00150 integer, Intent (Out) :: ierror
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 Integer, Parameter :: nrefd = 4 * 4 * 4
00166 Integer, Parameter :: lon = 1
00167 Integer, Parameter :: lat = 2
00168
00169 Double Precision, Parameter :: dble_earth = 6400.0
00170
00171 Double Precision, Parameter :: tol = 1d-6
00172 Double Precision, Parameter :: eps = 1d-6
00173 Double Precision, Parameter :: acosp1 = 1.0d0
00174 Double Precision, Parameter :: acosm1 = -1.0d0
00175
00176
00177
00178
00179
00180 Integer :: i, ibeg, iend, n
00181 Integer :: j, jbeg, jend
00182
00183 Integer, Pointer :: indices (:)
00184
00185
00186
00187 Double Precision, Pointer :: sin_search (:, :)
00188 Double Precision, Pointer :: cos_search (:, :)
00189 Double Precision, Pointer :: z_search (:)
00190
00191 Integer :: ijkctl (ndim_3d, nrefd)
00192 Integer :: ijkdst (ndim_3d, nrefd)
00193 Integer :: irange (2, ndim_3d)
00194 Integer :: itemp (ndim_3d)
00195
00196 Logical :: mask_dist (nrefd)
00197 Double Precision :: distance (nrefd), dist, fac, val
00198 Double Precision :: dist_control
00199
00200 Integer :: ijk (ndim_3d), ijk0 (ndim_3d)
00201 Integer :: leni, lenij
00202 Integer :: ii, jj, kk, nref
00203
00204 Integer :: nfound
00205 Integer :: nmin (1)
00206
00207
00208
00209 Double Precision :: dble_huge
00210
00211
00212
00213 Integer, Parameter :: nerrp = 2
00214 Integer :: ierrp (nerrp)
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 Character(len=len_cvs_string), save :: mycvs =
00237 '$Id: psmile_neigh_nearestx_3d_dble.F90 2325 2010-04-21 15:00:07Z valcke $'
00238
00239
00240
00241
00242
00243 #ifdef OLD
00244 Integer, Parameter :: nrefd = 3 * 3 * 3
00245
00246 data ((ijkctl (i, n), i=1,ndim_3d), n = 1,nrefd) &
00247 / 0, 0, 0, &
00248 1, 0, 0, 0, 1, 0, 0, 0, 1, &
00249 -1, 0, 0, 0,-1, 0, 0, 0,-1, &
00250 -1,-1, 0, 1,-1, 0, &
00251 -1, 1, 0, 1, 1, 0, &
00252 -1, 0,-1, 1, 0,-1, &
00253 -1, 0, 1, 1, 0, 1, &
00254 0,-1,-1, 0, 1,-1, &
00255 0,-1, 1, 0, 1, 1, &
00256 -1,-1,-1, 1,-1,-1, &
00257 -1, 1,-1, 1, 1,-1, &
00258 -1,-1, 1, 1,-1, 1, &
00259 -1, 1, 1, 1, 1, 1/
00260 #endif
00261
00262
00263
00264 data ((ijkctl (i, n), i=1,ndim_3d), n = 1,nrefd) &
00265 / 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, &
00266 0, 1, 0, 1, 1, 0, 2, 1, 0, 3, 1, 0, &
00267 0, 2, 0, 1, 2, 0, 2, 2, 0, 3, 2, 0, &
00268 0, 3, 0, 1, 3, 0, 2, 3, 0, 3, 3, 0, &
00269 0, 0, 1, 1, 0, 1, 2, 0, 1, 3, 0, 1, &
00270 0, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, &
00271 0, 2, 1, 1, 2, 1, 2, 2, 1, 3, 2, 1, &
00272 0, 3, 1, 1, 3, 1, 2, 3, 1, 3, 3, 1, &
00273 0, 0, 2, 1, 0, 2, 2, 0, 2, 3, 0, 2, &
00274 0, 1, 2, 1, 1, 2, 2, 1, 2, 3, 1, 2, &
00275 0, 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, 2, &
00276 0, 3, 2, 1, 3, 2, 2, 3, 2, 3, 3, 2, &
00277 0, 0, 3, 1, 0, 3, 2, 0, 3, 3, 0, 3, &
00278 0, 1, 3, 1, 1, 3, 2, 1, 3, 3, 1, 3, &
00279 0, 2, 3, 1, 2, 3, 2, 2, 3, 3, 2, 3, &
00280 0, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3/
00281
00282
00283
00284
00285
00286 #ifdef VERBOSE
00287 print 9990, trim(ch_id)
00288
00289 call psmile_flushstd
00290 #endif /* VERBOSE */
00291
00292 ierror = 0
00293
00294 ibeg = nprev + 1
00295 iend = nprev + nsearch
00296
00297 indices => extra_search%indices
00298
00299
00300
00301
00302 do jbeg = 1, extra_search%n_extra
00303 if (indices(jbeg) >= ibeg) exit
00304 end do
00305
00306 if (jbeg > extra_search%n_extra) return
00307
00308
00309 do jend = jbeg, extra_search%n_extra
00310 if (indices(jend) > iend) exit
00311 end do
00312 jend = jend - 1
00313
00314 if (jbeg > jend) return
00315
00316 ibeg = indices (jbeg)
00317 iend = indices (jend)
00318
00319 #ifdef PRISM_ASSERTION
00320
00321
00322
00323
00324 do j = jbeg, jend
00325 i = indices(j)
00326
00327 if (srcloc(1,i) < coords_shape(1,1) .or. &
00328 srcloc(1,i) > coords_shape(2,1) .or. &
00329 srcloc(2,i) < coords_shape(1,2) .or. &
00330 srcloc(2,i) > coords_shape(2,2) .or. &
00331 srcloc(3,i) < coords_shape(1,3) .or. &
00332 srcloc(3,i) > coords_shape(2,3)) exit
00333 end do
00334
00335 if (j <= jend) then
00336 print *, i, srcloc(:, i), coords_shape
00337 call psmile_assert (__FILE__, __LINE__, &
00338 'wrong index')
00339 endif
00340 #endif
00341
00342 dble_huge = huge (distance(1))
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 Allocate (sin_search(jbeg:jend, lat), STAT = ierror)
00356
00357 if ( ierror > 0 ) then
00358 ierrp (1) = ierror
00359 ierrp (2) = nsearch * lat
00360
00361 ierror = PRISM_Error_Alloc
00362 call psmile_error ( ierror, 'sin_search', &
00363 ierrp, 2, __FILE__, __LINE__ )
00364 return
00365 endif
00366
00367 Allocate (cos_search(jbeg:jend, lat), STAT = ierror)
00368
00369 if ( ierror > 0 ) then
00370 ierrp (1) = ierror
00371 ierrp (2) = nsearch * lat
00372
00373 ierror = PRISM_Error_Alloc
00374 call psmile_error ( ierror, 'cos_search', &
00375 ierrp, 2, __FILE__, __LINE__ )
00376 return
00377 endif
00378
00379 Allocate (z_search(jbeg:jend), STAT = ierror)
00380
00381 if ( ierror > 0 ) then
00382 ierrp (1) = ierror
00383 ierrp (2) = nsearch
00384
00385 ierror = PRISM_Error_Alloc
00386 call psmile_error ( ierror, 'z_search', &
00387 ierrp, 2, __FILE__, __LINE__ )
00388 return
00389 endif
00390
00391
00392 do j = jbeg, jend
00393 sin_search (j, lon) = coords1 (indices(j)) * dble_deg2rad
00394 end do
00395
00396
00397 do j = jbeg, jend
00398 sin_search (j, lat) = coords2 (indices(j)) * dble_deg2rad
00399 end do
00400
00401 cos_search = cos (sin_search)
00402 sin_search = sin (sin_search)
00403
00404
00405 do j = jbeg, jend
00406 z_search (j) = coords3 (indices(j))
00407 end do
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428 ijk0 = Grids(grid_id)%ijk0
00429
00430 do j = jbeg, jend
00431 i = indices(j)
00432
00433
00434
00435 ijk = ijk0 + ((srcloc(:,i) - ijk0) / 4) * 4
00436
00437
00438
00439 irange (1, :) = max (ijk, grid_valid_shape (1, :))
00440 irange (2, :) = min (ijk+3, grid_valid_shape (2, :))
00441
00442 nref = (irange (2,1) - irange (1,1) + 1) * &
00443 (irange (2,2) - irange (1,2) + 1) * &
00444 (irange (2,3) - irange (1,3) + 1)
00445
00446 if (nref == nrefd) then
00447 do n = 1, nrefd
00448 ijkdst (:, n) = ijk + ijkctl (:, n)
00449 end do
00450 else
00451
00452 leni = irange (2, 1) - irange (1, 1) + 1
00453 lenij = (irange (2, 2) - irange (1, 2) + 1) * leni
00454
00455 do kk = 1, irange (2,3)-irange(1,3) + 1
00456 n = (kk-1)*lenij
00457 do jj = 1, irange (2,2)-irange(1,2) + 1
00458
00459 do ii = 1, leni
00460 ijkdst (1, n+ii) = irange(1,1) + ii - 1
00461 end do
00462
00463 ijkdst (2, n+1:n+leni) = irange (1,2) + jj - 1
00464 n = n + leni
00465 end do
00466
00467 ijkdst (3, (kk-1)*lenij+1:kk*lenij) = irange (1,3) + kk - 1
00468 end do
00469 endif
00470
00471
00472
00473 if (mask_available) then
00474
00475 do n = 1, nref
00476 mask_dist (n) = mask_array (ijkdst (1,n), ijkdst (2,n), &
00477 ijkdst (3,n))
00478 end do
00479
00480 n = count (mask_dist(1:nref))
00481
00482 if (n == 0) then
00483
00484
00485 nref = 0
00486 go to 10
00487 endif
00488
00489 if (n < nref) then
00490 n = 0
00491 do ii = 1, nref
00492 if (mask_dist (ii)) then
00493 n = n + 1
00494 if (n /= ii) ijkdst (:, n) = ijkdst (:, ii)
00495 endif
00496 end do
00497 nref = n
00498 endif
00499 endif
00500
00501
00502
00503 fac = dble_earth + z_search (j)
00504
00505 do n = 1, nref
00506 val = ( sin_values(ijkdst (1,n), &
00507 ijkdst (2,n), &
00508 ijkdst (3,n), lat) * sin_search(j, lat) &
00509 + cos_values(ijkdst (1,n), &
00510 ijkdst (2,n), &
00511 ijkdst (3,n), lat) * cos_search(j, lat) &
00512 * (cos_values(ijkdst (1,n), &
00513 ijkdst (2,n), &
00514 ijkdst (3,n), lon) * cos_search(j, lon) &
00515 +sin_values(ijkdst (1,n), &
00516 ijkdst (2,n), &
00517 ijkdst (3,n), lon) * sin_search(j, lon)) )
00518 #ifdef PRISM_ASSERTION
00519 if (val < acosm1 - eps .or. val > acosp1 + eps) then
00520 print *, i, j, val
00521 call psmile_assert (__FILE__, __LINE__, &
00522 'invalid value for acos')
00523 endif
00524 #endif
00525 val = min (acosp1, val)
00526 val = max (acosm1, val)
00527
00528 dist = fac * acos (val)
00529
00530 distance (n) = dist*dist + &
00531 ( z_search (j)-z_coords(ijkdst (1,n), &
00532 ijkdst (2,n), &
00533 ijkdst (3,n)))**2
00534 #ifdef DEBUG2
00535 if (i == 2) then
00536 print *, 'dist, diff', dist, &
00537 z_search (j)-z_coords(ijkdst (1,n), ijkdst (2,n), ijkdst (3,n))
00538 endif
00539 #endif
00540 end do
00541
00542 nmin = minloc (distance(1:nref))
00543 #ifdef MINLOCFIX
00544 if (nmin(1).eq.0) nmin=1
00545 #endif /* MINLOCFIX */
00546
00547 #ifdef DEBUG2
00548 if (i == 2) then
00549 print *, 'psmile_neigh_nearestx_3d_dble: ictl =', i
00550 print *, 'ijkdst and distance:'
00551 do n = 1, nref
00552 print *, ijkdst (:, n), distance (n)
00553 end do
00554 endif
00555 #endif
00556
00557
00558
00559 if (distance(nmin(1)) <= tol) then
00560 neighbors_3d (:, i, 1) = ijkdst (:, nmin(1))
00561
00562 do n = 2, num_neigh
00563 neighbors_3d (:, i, n) = grid_valid_shape (1, :) - 1
00564 end do
00565
00566 cycle
00567 endif
00568
00569
00570
00571
00572 10 continue
00573
00574 nfound = min (num_neigh, nref)
00575 if (nfound < num_neigh) then
00576 distance(nfound+1:num_neigh) = dble_huge
00577
00578 do n = nfound+1, num_neigh
00579 ijkdst (:, n) = grid_valid_shape (1, :) - 1
00580 end do
00581 endif
00582
00583 do n = 1, nfound
00584
00585 nmin = minloc (distance(n:nref))
00586 #ifdef MINLOCFIX
00587 if (nmin(1).eq.0) nmin=1
00588 #endif /* MINLOCFIX */
00589
00590 if (nmin(1) /= 1) then
00591 jj = n + nmin (1) - 1
00592
00593 itemp (:) = ijkdst (:, n)
00594 ijkdst (:, n) = ijkdst (:, jj)
00595 ijkdst (:, jj) = itemp (:)
00596
00597 dist = distance (n)
00598 distance (n) = distance (jj)
00599 distance (jj) = dist
00600 endif
00601 end do
00602
00603 #ifdef PRISM_ASSERTION
00604 do n = 1, nfound-1
00605 if (distance(n) > distance (n+1)) exit
00606 end do
00607
00608 if (n <= nfound-1) then
00609 print *, 'n =' , n
00610 print *, 'distance (n) ', distance (n)
00611 print *, 'distance (n+1)', distance (n+1)
00612 print *, 'distance', distance (1:nfound)
00613 call psmile_assert (__FILE__, __LINE__, &
00614 'incorrect sort')
00615 endif
00616 #endif
00617
00618
00619
00620 dist_control = distance (num_neigh)
00621
00622 #ifdef TODO
00623 call psmile_mg_search_nneigh_3d_dble (distance, ijkdst, num_neigh, &
00624 grid_id, ierror)
00625 #endif /* TODO */
00626
00627
00628
00629 do n = 1, num_neigh
00630 neighbors_3d (:, i, n) = ijkdst (:, n)
00631 end do
00632
00633 end do
00634
00635
00636
00637 Deallocate (z_search)
00638 Deallocate (cos_search)
00639 Deallocate (sin_search)
00640
00641
00642
00643 #ifdef VERBOSE
00644 print 9980, trim(ch_id), ierror
00645
00646 call psmile_flushstd
00647 #endif /* VERBOSE */
00648
00649
00650
00651 9990 format (1x, a, ': psmile_neigh_nearestx_3d_dble')
00652 9980 format (1x, a, ': psmile_neigh_nearestx_3d_dble: eof, ierror =', i3)
00653
00654 end subroutine PSMILe_Neigh_nearestx_3d_dble