prismtrs_intersection.F90

Go to the documentation of this file.
00001 !------------------------------------------------------------------------
00002 ! Copyright 2006-2010, CERFACS, Toulouse, France.
00003 ! All rights reserved. Use is subject to OASIS4 license terms.
00004 !-----------------------------------------------------------------------
00005 !BOP
00006 !
00007 ! !ROUTINE: PRISMTrs_intersection
00008 !
00009 ! !INTERFACE!
00010       subroutine prismtrs_intersection(location,intrsct_lat,intrsct_lon,lcoinc, &
00011                              beglat, beglon, endlat, endlon, begseg, &
00012                              lbegin, lrevers, &
00013                              num_srch_cells, id_nbcorners, &
00014                              srch_corner_lat, srch_corner_lon, srch_add)
00015 
00016 !-----------------------------------------------------------------------
00017 !
00018 !     intent(in): 
00019 !
00020 !-----------------------------------------------------------------------
00021      !
00022         USE PRISMDrv, dummy_INTERFACE => PRISMTrs_intersection
00023         IMPLICIT NONE
00024 
00025         INTEGER, INTENT(in) :: num_srch_cells, id_nbcorners
00026         DOUBLE PRECISION, DIMENSION(id_nbcorners, num_srch_cells), INTENT(in) ::
00027            srch_corner_lat, srch_corner_lon
00028         INTEGER, DIMENSION(num_srch_cells), INTENT(in) :: srch_add
00029         !
00030       logical, intent(in) :: 
00031           lbegin,  ! flag for first integration along this segment
00032           lrevers ! flag whether segment integrated in reverse
00033 
00034       DOUBLE PRECISION, intent(in) :: 
00035           beglat, beglon,  ! beginning lat/lon endpoints for segment
00036           endlat, endlon   ! ending    lat/lon endpoints for segment
00037 
00038       DOUBLE PRECISION, dimension(2), intent(inout) :: 
00039           begseg ! begin lat/lon of full segment
00040 
00041 !-----------------------------------------------------------------------
00042 !
00043 !     intent(out): 
00044 !
00045 !-----------------------------------------------------------------------
00046 
00047       integer, intent(out) :: 
00048              location  ! address in destination array containing this
00049                         ! segment
00050 
00051       logical, intent(out) :: 
00052              lcoinc    ! flag segments which are entirely coincident
00053                         ! with a grid line
00054 
00055       DOUBLE PRECISION, intent(out) :: 
00056           intrsct_lat, intrsct_lon ! lat/lon coords of next intersect.
00057 !
00058 ! !DESCRIPTION
00059 !
00060 ! SUBROUTINE PRISMTrs_intersection finds the next intersection of a 
00061 !     destination grid 
00062 !     line with the line segment given by beglon, endlon, etc.
00063 !     a coincidence flag is returned if the segment is entirely 
00064 !     coincident with an ocean grid line.  the cells in which to search
00065 !     for an intersection must have already been restricted in the
00066 !     calling routine.
00067 !     This routine comes from the SCRIP 1.4 library available 
00068 !     from Los Alamos National Laboratory.
00069 !
00070 ! !REVISED HISTORY
00071 !   Date      Programmer   Description
00072 ! ----------  ----------   -----------
00073 ! 21/03/2007  S. Valcke    Duplicated from the SCRIP library
00074 !
00075 ! EOP
00076 !----------------------------------------------------------------------
00077 ! $Id: prismtrs_intersection.F90 2082 2009-10-21 13:31:19Z hanke $
00078 ! $Author: hanke $
00079 !----------------------------------------------------------------------
00080 
00081 !-----------------------------------------------------------------------
00082 !
00083 !     local variables
00084 !
00085 !-----------------------------------------------------------------------
00086       CHARACTER(LEN=len_cvs_string), SAVE  :: mycvs = 
00087      '$Id: prismtrs_intersection.F90 2082 2009-10-21 13:31:19Z hanke $'
00088       integer :: n, next_n, cell, srch_corners
00089 ! for test of non-convexe cell
00090       INTEGER :: next2_n, neg, pos  
00091 
00092       integer, save :: 
00093           last_loc  ! save location when crossing threshold
00094 
00095       logical :: 
00096           loutside  ! flags points outside grid
00097 
00098       logical, save :: 
00099           lthresh = .false.  ! flags segments crossing threshold bndy
00100 
00101       DOUBLE PRECISION :: 
00102           lon1, lon2,       ! local longitude variables for segment
00103           lat1, lat2,       ! local latitude  variables for segment
00104           grdlon1, grdlon2,  ! local longitude variables for grid cell
00105           grdlat1, grdlat2,  ! local latitude  variables for grid cell
00106           vec1_lat, vec1_lon,  ! vectors and cross products used
00107           vec2_lat, vec2_lon,  ! during grid search
00108           cross_product, 
00109           eps, offset,        ! small offset away from intersect
00110           s1, s2, determ,     ! variables used for linear solve to
00111           mat1, mat2, mat3, mat4, rhs1, rhs2,  ! find intersection
00112           rl_halfpi, rl_v2lonmpi2, rl_v2lonppi2
00113 
00114       DOUBLE PRECISION, save :: 
00115           intrsct_lat_off, intrsct_lon_off ! lat/lon coords offset 
00116                                             ! for next search
00117 
00118 #ifdef DEBUGX
00119       INTEGER, PARAMETER :: nbr_tgt_cells = 13
00120       INTEGER, DIMENSION(nbr_tgt_cells)  :: grid_tgt  ! EPIO target number of the target cell under investigation
00121       INTEGER :: ii
00122       DOUBLE PRECISION, PARAMETER :: dbl_rad2deg = 360.0/6.2831853
00123 #endif
00124 
00125 #ifdef DEBUGX
00126   PRINT *, '| | | | | | | Enter PRISMTrs_intersection'
00127   call psmile_flushstd
00128 #endif
00129 !-----------------------------------------------------------------------
00130 !
00131 !     initialize defaults, flags, etc.
00132 !
00133 !-----------------------------------------------------------------------
00134 #ifdef DEBUGX
00135   grid_tgt(1)= 7215
00136   grid_tgt(2)= 7216
00137   grid_tgt(3)= 7251
00138   grid_tgt(4)= 7252
00139   grid_tgt(5)= 7253
00140   grid_tgt(6)= 7254
00141   grid_tgt(7)= 7279
00142   grid_tgt(8)= 7280
00143   grid_tgt(9)= 7281
00144   grid_tgt(10)= 7282
00145   grid_tgt(11)= 7290
00146   grid_tgt(12)= 7291
00147   grid_tgt(13)= 7292
00148 #endif
00149 
00150       location = 0
00151       lcoinc = .false.
00152       intrsct_lat = endlat
00153       intrsct_lon = endlon
00154 
00155       if (num_srch_cells == 0) return
00156 
00157       if (beglat > north_thresh .or. beglat < south_thresh) then
00158 
00159         if (lthresh) location = last_loc
00160         call prismtrs_pole_intersection(location, &
00161                      intrsct_lat,intrsct_lon,lcoinc,lthresh, &
00162                      beglat, beglon, endlat, endlon, begseg, lrevers, &
00163                      num_srch_cells, id_nbcorners, &
00164                      srch_corner_lat, srch_corner_lon, srch_add)
00165         if (lthresh) then
00166           last_loc = location
00167           intrsct_lat_off = intrsct_lat
00168           intrsct_lon_off = intrsct_lon
00169         endif
00170         return
00171 
00172       endif
00173 
00174       loutside = .false.
00175       if (lbegin) then
00176         lat1 = beglat
00177         lon1 = beglon
00178       else
00179         lat1 = intrsct_lat_off
00180         lon1 = intrsct_lon_off
00181       endif
00182       lat2 = endlat
00183       lon2 = endlon
00184       if ((lon2-lon1) > three*dble_pih) then
00185         lon2 = lon2 - dble_pi2
00186       else if ((lon2-lon1) < -three*dble_pih) then
00187         lon2 = lon2 + dble_pi2
00188       endif
00189       s1 = zero
00190 !-----------------------------------------------------------------------
00191 !
00192 !     search for location of this segment in ocean grid using cross
00193 !     product method to determine whether a point is enclosed by a cell
00194 !
00195 !-----------------------------------------------------------------------
00196 
00197 !      call timer_start(12)
00198       srch_corners = size(srch_corner_lat,DIM=1)
00199       srch_loop: do
00200 
00201         !***
00202         !*** if last segment crossed threshold, use that location
00203         !***
00204 
00205         if (lthresh) then
00206           do cell=1,num_srch_cells
00207             if (srch_add(cell) == last_loc) then
00208               location = last_loc
00209               eps = tiny
00210               exit srch_loop
00211             endif
00212           end do
00213         endif
00214 
00215         !***
00216         !*** otherwise normal search algorithm
00217         !***
00218 
00219         cell_loop: DO cell=1,num_srch_cells
00220           corner_loop: do n=1,srch_corners
00221             next_n = MOD(n,srch_corners) + 1
00222 
00223             !***
00224             !*** here we take the cross product of the vector making 
00225             !*** up each cell side with the vector formed by the vertex
00226             !*** and search point.  if all the cross products are 
00227             !*** positive, the point is contained in the cell.
00228             !***
00229 
00230             vec1_lat = srch_corner_lat(next_n,cell) -  &
00231                       srch_corner_lat(n     ,cell)
00232             vec1_lon = srch_corner_lon(next_n,cell) -  &
00233                       srch_corner_lon(n     ,cell)
00234             vec2_lat = lat1 - srch_corner_lat(n,cell)
00235             vec2_lon = lon1 - srch_corner_lon(n,cell)
00236 
00237             !***
00238             !*** if endpoint coincident with vertex, offset
00239             !*** the endpoint
00240             !***
00241 
00242             if (vec2_lat == 0 .and. vec2_lon == 0) then
00243               lat1 = lat1 + 1.d-10*(lat2-lat1)
00244               lon1 = lon1 + 1.d-10*(lon2-lon1)
00245               vec2_lat = lat1 - srch_corner_lat(n,cell)
00246               vec2_lon = lon1 - srch_corner_lon(n,cell)
00247             ENDIF
00248 
00249             !***
00250             !*** check for 0,2pi crossings
00251             !***
00252 
00253             if (vec1_lon >  dble_pi) then
00254               vec1_lon = vec1_lon - dble_pi2
00255             else if (vec1_lon < -dble_pi) then
00256               vec1_lon = vec1_lon + dble_pi2
00257             endif
00258             if (vec2_lon >  dble_pi) then
00259               vec2_lon = vec2_lon - dble_pi2
00260             else if (vec2_lon < -dble_pi) then
00261               vec2_lon = vec2_lon + dble_pi2
00262             endif
00263 
00264             cross_product = vec1_lon*vec2_lat - vec2_lon*vec1_lat
00265 
00266             !***
00267             !*** if the cross product for a side is zero, the point 
00268             !***   lies exactly on the side or the side is degenerate
00269             !***   (zero length).  if degenerate, set the cross 
00270             !***   product to a positive number.  otherwise perform 
00271             !***   another cross product between the side and the 
00272             !***   segment itself. 
00273             !*** if this cross product is also zero, the line is 
00274             !***   coincident with the cell boundary - perform the 
00275             !***   dot product and only choose the cell if the dot 
00276             !***   product is positive (parallel vs anti-parallel).
00277             !***
00278 
00279             if (cross_product == zero) then
00280               if (vec1_lat /= zero .or. vec1_lon /= zero) then
00281                 vec2_lat = lat2 - lat1
00282                 vec2_lon = lon2 - lon1
00283 
00284                 if (vec2_lon >  dble_pi) then
00285                   vec2_lon = vec2_lon - dble_pi2
00286                 else if (vec2_lon < -dble_pi) then
00287                   vec2_lon = vec2_lon + dble_pi2
00288                 endif
00289 
00290                 cross_product = vec1_lon*vec2_lat - vec2_lon*vec1_lat
00291               else
00292                 cross_product = one
00293               endif
00294 
00295               if (cross_product == zero) then
00296                 lcoinc = .true.
00297                 cross_product = vec1_lon*vec2_lon + vec1_lat*vec2_lat
00298                 if (lrevers) cross_product = -cross_product
00299               endif
00300             endif
00301 
00302 #ifdef DEBUGX
00303             DO ii = 1,nbr_tgt_cells
00304               IF (srch_add(cell) == grid_tgt(ii) ) THEN
00305                   WRITE(88,*) 'lrevers :',lrevers
00306                   WRITE(88,1110) srch_add(cell),n,next_n
00307                   WRITE(88,1111) dbl_rad2deg*lon1,dbl_rad2deg*lat1
00308                   WRITE(88,1112) dbl_rad2deg*lon2,dbl_rad2deg*lat2
00309                   WRITE(88,1113) cross_product
00310               ENDIF
00311             ENDDO
00312 !
00313  1110 FORMAT ('    grid2 cell, corners = ', 2X, I6, 2X, I2, 2X, I2)
00314  1111 format ('    lon1, lat1 = ', 2X, F12.4, 2X, F12.4)
00315  1112 format ('    lon2, lat2 = ', 2X, F12.4, 2X, F12.4)
00316  1113 format ('    cross_product  = ', 2X, F12.6)
00317 #endif
00318 
00319             !***
00320             !*** if cross product is less than zero, this cell
00321             !*** doesn't work
00322             !***
00323             if (cross_product < zero) exit corner_loop
00324           end do corner_loop
00325 
00326           !***
00327           !*** if cross products all positive, we found the location
00328           !***
00329 
00330           if (n > srch_corners) then
00331             location = srch_add(cell)
00332 
00333             !***
00334             !*** if the beginning of this segment was outside the
00335             !*** grid, invert the segment so the intersection found
00336             !*** will be the first intersection with the grid
00337             !***
00338             if (loutside) then
00339                !*** do a test to see if the cell really is outside 
00340                !*** or if it is a non-convexe cell 
00341                neg=0
00342                pos=0
00343                do n=1,srch_corners
00344                   next_n = MOD(n,srch_corners) + 1
00345                   next2_n = MOD(next_n,srch_corners) + 1
00346 
00347                   vec1_lat = srch_corner_lat(next_n,cell) - &
00348                       srch_corner_lat(n,cell)
00349                   vec1_lon = srch_corner_lon(next_n,cell) - &
00350                       srch_corner_lon(n,cell)
00351                   vec2_lat = srch_corner_lat(next2_n,cell) - &
00352                       srch_corner_lat(next_n,cell)
00353                   vec2_lon =  srch_corner_lon(next2_n,cell) - & 
00354                       srch_corner_lon(next_n,cell)
00355                   
00356                   if (vec1_lon > three*dble_pih) then
00357                      vec1_lon = vec1_lon - dble_pi2
00358                   else if (vec1_lon < -three*dble_pih) then
00359                      vec1_lon = vec1_lon + dble_pi2
00360                   endif
00361                   
00362                   if (vec2_lon > three*dble_pih) then
00363                      vec2_lon = vec2_lon - dble_pi2
00364                   else if (vec2_lon < -three*dble_pih) then
00365                      vec2_lon = vec2_lon + dble_pi2
00366                   endif
00367                   
00368                   cross_product= &
00369                       vec1_lat*vec2_lon - vec2_lat*vec1_lon
00370 
00371                   if (cross_product < zero) then
00372                      neg=neg+1
00373                   else if (cross_product > zero) then
00374                      pos=pos+1
00375                   endif
00376                enddo
00377                !*** the cell is non-convexe if not all cross_products 
00378                !*** have the same signe
00379                if (neg/=0 .and. pos/=0) then
00380                   loutside=.false.
00381                   print*, 'The mesh ',srch_add(cell),' is non-convex'
00382                   print*, 'srch_corner_lat=',srch_corner_lat(:,cell)
00383                   print*, 'srch_corner_lon=',srch_corner_lon(:,cell)
00384                endif
00385             endif
00386             if (loutside) then
00387               lat2 = beglat
00388               lon2 = beglon
00389               location = 0
00390               eps  = -tiny
00391             else
00392               eps  = tiny
00393             endif
00394             exit srch_loop
00395           endif
00396 
00397           !***
00398           !*** otherwise move on to next cell
00399           !***
00400         end do cell_loop
00401 
00402         !***
00403         !*** if still no cell found, the point lies outside the grid.
00404         !***   take some baby steps along the segment to see if any
00405         !***   part of the segment lies inside the grid.  
00406         !***
00407 
00408         loutside = .true.
00409         s1 = s1 + baby
00410         lat1 = beglat + s1*(endlat - beglat)
00411         lon1 = beglon + s1*(lon2   - beglon)
00412 
00413         !***
00414         !*** reached the end of the segment and still outside the grid
00415         !*** return no intersection
00416         !***
00417         if (s1 >= one) return
00418 
00419       end do srch_loop
00420 !      call timer_stop(12)
00421 
00422 !-----------------------------------------------------------------------
00423 !
00424 !     now that a cell is found, search for the next intersection.
00425 !     loop over sides of the cell to find intersection with side
00426 !     must check all sides for coincidences or intersections
00427 !
00428 !-----------------------------------------------------------------------
00429 
00430 !      call timer_start(13)
00431       intrsct_loop: do n=1,srch_corners
00432         next_n = mod(n,srch_corners) + 1
00433 
00434         grdlon1 = srch_corner_lon(n     ,cell)
00435         grdlon2 = srch_corner_lon(next_n,cell)
00436         grdlat1 = srch_corner_lat(n     ,cell)
00437         grdlat2 = srch_corner_lat(next_n,cell)
00438 
00439         !***
00440         !*** set up linear system to solve for intersection
00441         !***
00442 
00443         mat1 = lat2 - lat1
00444         mat2 = grdlat1 - grdlat2
00445         mat3 = lon2 - lon1
00446         mat4 = grdlon1 - grdlon2
00447         rhs1 = grdlat1 - lat1
00448         rhs2 = grdlon1 - lon1
00449 
00450         if (mat3 >  dble_pi) then
00451           mat3 = mat3 - dble_pi2
00452         else if (mat3 < -dble_pi) then
00453           mat3 = mat3 + dble_pi2
00454         endif
00455         if (mat4 >  dble_pi) then
00456           mat4 = mat4 - dble_pi2
00457         else if (mat4 < -dble_pi) then
00458           mat4 = mat4 + dble_pi2
00459         endif
00460         if (rhs2 >  dble_pi) then
00461           rhs2 = rhs2 - dble_pi2
00462         else if (rhs2 < -dble_pi) then
00463           rhs2 = rhs2 + dble_pi2
00464         endif
00465 
00466         determ = mat1*mat4 - mat2*mat3
00467 
00468         !***
00469         !*** if the determinant is zero, the segments are either 
00470         !***   parallel or coincident.  coincidences were detected 
00471         !***   above so do nothing.
00472         !*** if the determinant is non-zero, solve for the linear 
00473         !***   parameters s for the intersection point on each line 
00474         !***   segment.
00475         !*** if 0<s1,s2<1 then the segment intersects with this side.
00476         !***   return the point of intersection (adding a small
00477         !***   number so the intersection is off the grid line).
00478         !***
00479 
00480         if (abs(determ) > 1.e-30) then
00481 
00482           s1 = (rhs1*mat4 - mat2*rhs2)/determ
00483           s2 = (mat1*rhs2 - rhs1*mat3)/determ
00484 
00485           if (s2 >= zero .and. s2 <= one .and. &
00486              s1 >  zero .and. s1 <= one) then
00487 
00488             !***
00489             !*** recompute intersection based on full segment
00490             !*** so intersections are consistent for both sweeps
00491             !***
00492 
00493             if (.not. loutside) then
00494               mat1 = lat2 - begseg(1)
00495               mat3 = lon2 - begseg(2)
00496               rhs1 = grdlat1 - begseg(1)
00497               rhs2 = grdlon1 - begseg(2)
00498             else
00499               mat1 = begseg(1) - endlat
00500               mat3 = begseg(2) - endlon
00501               rhs1 = grdlat1 - endlat
00502               rhs2 = grdlon1 - endlon
00503             endif
00504 
00505             if (mat3 >  dble_pi) then
00506               mat3 = mat3 - dble_pi2
00507             else if (mat3 < -dble_pi) then
00508               mat3 = mat3 + dble_pi2
00509             endif
00510             if (rhs2 >  dble_pi) then
00511               rhs2 = rhs2 - dble_pi2
00512             else if (rhs2 < -dble_pi) then
00513               rhs2 = rhs2 + dble_pi2
00514             endif
00515 
00516             determ = mat1*mat4 - mat2*mat3
00517 
00518             !***
00519             !*** sometimes due to roundoff, the previous 
00520             !*** determinant is non-zero, but the lines
00521             !*** are actually coincident.  if this is the
00522             !*** case, skip the rest.
00523             !***
00524 
00525             if (determ /= zero) then
00526               s1 = (rhs1*mat4 - mat2*rhs2)/determ
00527               s2 = (mat1*rhs2 - rhs1*mat3)/determ
00528 
00529               offset = s1 + eps/determ
00530               if (offset > one) offset = one
00531 
00532               if (.not. loutside) then
00533                 intrsct_lat = begseg(1) + mat1*s1
00534                 intrsct_lon = begseg(2) + mat3*s1
00535                 intrsct_lat_off = begseg(1) + mat1*offset
00536                 intrsct_lon_off = begseg(2) + mat3*offset
00537               else
00538                 intrsct_lat = endlat + mat1*s1
00539                 intrsct_lon = endlon + mat3*s1
00540                 intrsct_lat_off = endlat + mat1*offset
00541                 intrsct_lon_off = endlon + mat3*offset
00542               endif
00543               exit intrsct_loop
00544             endif
00545 
00546           endif
00547         endif
00548 
00549         !***
00550         !*** no intersection this side, move on to next side
00551         !***
00552 
00553       end do intrsct_loop
00554 !      call timer_stop(13)
00555 
00556 !-----------------------------------------------------------------------
00557 !
00558 !     if the segment crosses a pole threshold, reset the intersection
00559 !     to be the threshold latitude.  only check if this was not a
00560 !     threshold segment since sometimes coordinate transform can end
00561 !     up on other side of threshold again.
00562 !
00563 !-----------------------------------------------------------------------
00564 
00565       if (lthresh) then
00566         if (intrsct_lat < north_thresh .or. intrsct_lat > south_thresh) &
00567            lthresh = .false.
00568       else if (lat1 > zero .and. intrsct_lat > north_thresh) then
00569         intrsct_lat = north_thresh + tiny
00570         intrsct_lat_off = north_thresh + eps*mat1
00571         s1 = (intrsct_lat - begseg(1))/mat1
00572         intrsct_lon     = begseg(2) + s1*mat3
00573         intrsct_lon_off = begseg(2) + (s1+eps)*mat3
00574         last_loc = location
00575         lthresh = .true.
00576       else if (lat1 < zero .and. intrsct_lat < south_thresh) then
00577         intrsct_lat = south_thresh - tiny
00578         intrsct_lat_off = south_thresh + eps*mat1
00579         s1 = (intrsct_lat - begseg(1))/mat1
00580         intrsct_lon     = begseg(2) + s1*mat3
00581         intrsct_lon_off = begseg(2) + (s1+eps)*mat3
00582         last_loc = location
00583         lthresh = .true.
00584       endif
00585 
00586 #ifdef DEBUGX
00587   PRINT *, '| | | | | | | Quit PRISMTrs_intersection'
00588   call psmile_flushstd
00589 #endif
00590 
00591 !-----------------------------------------------------------------------
00592 
00593       end subroutine prismtrs_intersection
00594 
00595 !***********************************************************************

Generated on 18 Mar 2011 for Oasis4 by  doxygen 1.6.1