-
GUEZ Lionel authoredGUEZ Lionel authored
get_1_outerm.f90 8.32 KiB
module get_1_outerm_m
implicit none
contains
subroutine get_1_outerm(out_cont, cont_list, cont_list_proj, n_cont, &
cyclone, extr_coord_proj, innermost_level_2, outside_points, ssh, &
corner, step)
! This procedure gets one outermost good contour with sufficient
! area, if it can find one. If the procedure cannot find an
! outermost contour, it returns a null ssh_contour. The procedure
! also returns some inner good contours. The maximum number of
! inner good contours returned is given by the size of cont_list -
! 1. If we find more inner good contours, then we return only the
! first ones found, because they provide a better sample of the
! ssh range. If the procedure cannot find an outermost contour, it
! does not return any inner contour. An outermost contour is not
! returned if there is no good contour at innermost_level_2 or if
! the outermost contour does not have sufficient area. If an
! outermost contour is found then its level is farther from the
! extremum than innermost_level_2. The outermost contour is
! duplicated in the array cont_list. In cont_list_proj, the
! contours, including the outermost contour, are in monotonic
! order of ssh: ascending if the extremum is a minimum, descending
! if the extremum is a maximum. The area is not computed for
! contours in cont_list_proj. On return, the array
! abs(ediff1d(cont_list_proj(:n_cont)%ssh)) is in descending
! order. (See notes for a proof.) On return, n_cont == 1 means we
! have only found one good contour at innermost_level_2 and it has
! sufficient area. On return, n_cont == 0 .eqv. out_cont ==
! null_polyline().
! Method: dichotomy on level of ssh.
! The length of the interval of longitudes of the domain, step(1)
! * (size(ssh, 1) - 1), should be < 180 degrees, so that the
! geometrical processing done here is non-ambiguous. The
! longitudes of outside points and the target extremum should be
! in the interval [corner(1), corner(1) + step(1) * (size(ssh, 1)
! - 1)] as there will be no automatic shifting by a mulitple of
! 360 degrees.
! Libraries:
use contour_531, only: polyline, convert_to_reg_coord, convert_to_ind
use jumble, only: assert
use ccw_orient_m, only: ccw_orient
use config_m, only: min_area
use derived_types, only: ssh_contour, null_ssh_contour
use good_contour_m, only: good_contour
use input_ssh_m, only: corner_whole => corner
use spher_polyline_area_m, only: spher_polyline_area
type(ssh_contour), intent(out):: out_cont
! points given by longitude, latitude, in rad
type(polyline), intent(out):: cont_list(:) ! (n_max_cont)
! Contour list, with points given by longitude and latitude, in
! radians. Defined only for subscripts 1:n_cont. If n_cont >= 1,
! the outermost contour is element with subscript n_cont. For i <=
! n_cont, the order of points in cont_list(i) (clockwise or
! counter-clockwise) is not specified.
type(ssh_contour), intent(out):: cont_list_proj(:) ! (n_max_cont)
! Contour list, with points given by projection
! coordinates. Defined only for subscripts 1:n_cont. If n_cont >=
! 1, the outermost contour is element with subscript n_cont. The
! contours are in monotonic order of ssh. The contour with a given
! subscript in cont_list_proj corresponds to the contour with the
! same subscript in cont_list. More precisely, the point with
! subscript j in contour i of cont_list_proj corresponds to the
! point with subscript j in contour i of cont_list (this is
! important for mean_speed). For i <= n_cont,
! cont_list_proj(i)%area has its default initialization value and
! the order of points in cont_list_proj(i) (clockwise or
! counter-clockwise) is not specified.
integer, intent(out):: n_cont
! number of good contours found and stored, 0 <= n_cont <= n_max_cont - 1
logical, intent(in):: cyclone
real, intent(in):: extr_coord_proj(:) ! (2)
! coordinates of extremum in projection space
real, intent(in):: innermost_level_2
! ssh level of the innermost contour to consider around the target
! extremum, in m. Assume: innermost_level_2 < extremum for a
! maximum, > extremum for a minimum.
real, intent(in):: outside_points(:, :) ! (2, :) longitude and
! latitude, in rad, of all the significant extrema, except the
! target extremum
real, intent(in):: ssh(:, :) ! in m
real, intent(in):: corner(:) ! (2)
! Longitude and latitude corresponding to ssh(1,1), in rad. A
! priori, this is not the corner of the grid of the NetCDF file.
real, intent(in):: step(:) ! (2)
! longitude and latitude steps, in rad
! Local:
real level_try, level_good, level_bad ! in m
real, parameter:: precision = 5e-4 ! in m
logical mask(size(ssh, 1), size(ssh, 2))
integer n_max_cont ! >= 3
integer i
real corner_proj(2)
real outside_points_proj(2, size(outside_points, 2))
!-----------------------------------------------------------------
corner_proj = (corner - corner_whole) / step + 1.
outside_points_proj = convert_to_ind(outside_points, corner_whole, step)
n_max_cont = size(cont_list_proj)
n_cont = 0
cont_list_proj(1)%polyline = good_contour(corner_proj, ssh, &
innermost_level_2, extr_coord_proj, outside_points_proj)
test_n_points: if (.not. cont_list_proj(1)%closed) then
! cont_list_proj(1)%n_points == 0
out_cont = null_ssh_contour()
else test_n_points
n_cont = 1
cont_list_proj(1)%ssh = innermost_level_2
level_good = innermost_level_2
mask = ssh /= huge(0.)
level_try = merge(maxval(ssh, mask), minval(ssh, mask), cyclone)
call assert(merge(level_try > level_good, level_try < level_good, &
cyclone), "get_1_outerm level_try")
cont_list_proj(2)%polyline = good_contour(corner_proj, ssh, level_try, &
extr_coord_proj, outside_points_proj)
if (cont_list_proj(2)%closed) then
! cont_list_proj(2)%n_points /= 0
! This can only happen if there are degenerate extrema
! everywhere around the path of contour. So it should
! probably never happen.
n_cont = 2
cont_list_proj(2)%ssh = level_try
else
! Assertion: {no good contour at maxval or minval}
level_bad = level_try
do while (abs(level_bad - level_good) > precision)
level_try = (level_good + level_bad) / 2.
cont_list_proj(n_cont + 1)%polyline = good_contour(corner_proj, &
ssh, level_try, extr_coord_proj, outside_points_proj)
if (cont_list_proj(n_cont + 1)%closed) then
! cont_list_proj(n_cont + 1)%n_points /= 0
cont_list_proj(n_cont + 1)%ssh = level_try
if (n_cont == n_max_cont - 1) then
! Replace the previous good contour found
cont_list_proj(n_cont) = cont_list_proj(n_max_cont)
else
n_cont = n_cont + 1
end if
level_good = level_try
else
level_bad = level_try
end if
! Assertion: cont_list_proj(n_cont)%polyline ==
! good_contour(. . ., level_good) and
! cont_list_proj(n_cont)%closed and no good contour at
! level_bad
end do
! Assertion: n_cont <= n_max_cont - 1
end if
out_cont%polyline &
= convert_to_reg_coord(cont_list_proj(n_cont)%polyline, &
corner_whole, step)
out_cont%area = spher_polyline_area(out_cont%polyline)
if (abs(out_cont%area) < min_area) then
out_cont = null_ssh_contour()
n_cont = 0
else
! n_cont >= 1
forall (i = 1:n_cont - 1) cont_list(i) &
= convert_to_reg_coord(cont_list_proj(i)%polyline, &
corner_whole, step)
cont_list(n_cont) = out_cont%polyline
out_cont%ssh = cont_list_proj(n_cont)%ssh
call ccw_orient(out_cont)
! (Note we have to orient out_cont after copying it to
! cont_list, so that cont_list corresponds to cont_list_proj
! point by point.)
end if
end if test_n_points
end subroutine get_1_outerm
end module get_1_outerm_m