From 6c00adf7d85273ad83884e1c6e50d7d7d79992dd Mon Sep 17 00:00:00 2001
From: Lionel GUEZ <guez@lmd.ens.fr>
Date: Fri, 2 Jun 2023 12:07:01 +0200
Subject: [PATCH] Create program `examine_eddy`

---
 Common/CMakeLists.txt              |   2 +
 Inst_eddies/CMakeLists.txt         |   4 +
 Inst_eddies/Tests/CMakeLists.txt   |  11 +-
 Inst_eddies/Tests/examine_eddy.f90 | 186 +++++++++++++++++++++++++++++
 4 files changed, 202 insertions(+), 1 deletion(-)
 create mode 100644 Inst_eddies/Tests/examine_eddy.f90

diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt
index 06e267a0..732cdcce 100644
--- a/Common/CMakeLists.txt
+++ b/Common/CMakeLists.txt
@@ -12,6 +12,8 @@ target_sources(inst_eddies PRIVATE spher_polyline_area.f90
   get_slice_dir.f90 read_field_indices.f90)
 target_sources(test_write_null PRIVATE derived_types.f90 shpc_open.f90
   shpc_close.f90 read_field_indices.f90 get_slice_dir.f90)
+target_sources(examine_eddy PRIVATE derived_types.f90 get_slice_dir.f90
+  spher_polyline_area.f90 shpc_close.f90)
 
 if(MPI_Fortran_HAVE_F08_MODULE)
   target_sources(test_overlap PRIVATE derived_types.f90 spher_polyline_area.f90
diff --git a/Inst_eddies/CMakeLists.txt b/Inst_eddies/CMakeLists.txt
index cd13b6df..d6ca08b6 100644
--- a/Inst_eddies/CMakeLists.txt
+++ b/Inst_eddies/CMakeLists.txt
@@ -30,3 +30,7 @@ target_sources(test_set_max_speed PRIVATE set_max_speed.F90 good_contour.f90
   ccw_orient.f90 write_eddy.f90 complete_ssh.f90)
 target_sources(test_write_null PRIVATE shpc_create.f90)
 target_sources(test_complete_ssh PRIVATE complete_ssh.f90)
+target_sources(examine_eddy PRIVATE config.f90 input_ssh.f90 get_var.f90
+  shpc_create.f90 set_all_extr.f90 local_extrema.f90 write_eddy.f90
+  set_contours.f90 get_1_outerm.f90 ccw_orient.f90 good_contour.f90
+  set_max_speed.F90 complete_ssh.f90 mean_speed.f90)
diff --git a/Inst_eddies/Tests/CMakeLists.txt b/Inst_eddies/Tests/CMakeLists.txt
index 2324f7b6..734af5e1 100644
--- a/Inst_eddies/Tests/CMakeLists.txt
+++ b/Inst_eddies/Tests/CMakeLists.txt
@@ -46,8 +46,17 @@ target_link_libraries(test_complete_ssh PRIVATE Jumble::jumble)
 # inst_eddies
 target_sources(inst_eddies PRIVATE cont_list.f90)
 
+# examine_eddies
+add_executable(examine_eddy examine_eddy.f90 cont_list.f90
+  ${PROJECT_SOURCE_DIR}/Overlap/read_eddy.f90)
+target_link_libraries(examine_eddy PRIVATE Contour_531::contour_531
+  Jumble::jumble Shapelib_03::shapelib_03 NetCDF95::netcdf95 gpc_f
+  Geometry::geometry Numer_Rec_95::numer_rec_95)
+target_compile_definitions(examine_eddy PRIVATE $<$<CONFIG:Debug>:DEBUG>)
+
 foreach(my_target IN ITEMS test_get_1_outerm test_good_contour test_mean_speed
-    test_nearby_extr test_local_extrema test_set_max_speed test_complete_ssh)
+    test_nearby_extr test_local_extrema test_set_max_speed test_complete_ssh
+    examine_eddy)
   set_target_properties(${my_target} PROPERTIES Fortran_MODULE_DIRECTORY
     ${CMAKE_CURRENT_BINARY_DIR}/${my_target}_modules)
   target_include_directories(${my_target} PRIVATE
diff --git a/Inst_eddies/Tests/examine_eddy.f90 b/Inst_eddies/Tests/examine_eddy.f90
new file mode 100644
index 00000000..f25fca9d
--- /dev/null
+++ b/Inst_eddies/Tests/examine_eddy.f90
@@ -0,0 +1,186 @@
+program examine_eddy
+
+  ! Libraries:
+  use contour_531, only: convert_to_ind
+  use jumble, only: get_command_arg_dyn, read_column, deg_to_rad, pi, &
+       rad_to_deg, twopi
+  use shapelib, only: shpfileobject, shpclose
+  use shapelib_03, only: dbf_read_attribute_03, dbf_get_field_index_03, &
+       shp_read_point, shp_open_03
+
+  use config_m, only: config, min_radius
+  use cont_list_m, only: create_cont_list, close_cont_list
+  use derived_types, only: snapshot, shpc_slice_handler, eddy, missing_ssh
+  use input_ssh_m, only: input_ssh, max_radius
+  use read_eddy_m, only: read_eddy
+  use shpc_create_m, only: shpc_create
+  use set_all_extr_m, only: set_all_extr
+  use set_contours_m, only: set_contours
+  use shpc_close_m, only: shpc_close
+  use write_eddy_m, only: write_eddy
+
+  implicit none
+
+  integer:: date = huge(0), eddy_i_target = huge(0)
+  integer ishape_first, d0, ishape, i, l, n1, n2, number_extr
+  logical:: cyclone = .true. ! orientation of target eddy
+  namelist /main_nml/ cyclone, date, eddy_i_target
+  TYPE(shpfileobject) hshp
+  character(len = :), allocatable:: slice_dir, slice_o_dir
+  type(eddy) e
+  integer extr_date ! field index in DBF file
+
+  integer, allocatable:: ishape_last(:) ! (d0:)
+  ! shape index (0-based) in the collection of shapefiles of the last
+  ! shape at a given date index
+
+  real corner(2)
+  ! longitude and latitude of the corner of the whole grid, in rad
+
+  real step(2) ! longitude and latitude steps, in rad
+  logical periodic ! grid is periodic in longitude
+
+  real, allocatable:: ssh(:, :)
+  ! (1 - max_radius(1):nlon + max_radius(1), nlat) if the grid is periodic
+  ! in longitude, else (nlon, nlat). Sea-surface height, in m.
+
+  real, allocatable:: u(:, :), v(:, :)
+  ! (1 - max_radius(1):nlon + max_radius(1), nlat) if periodic, else
+  ! (nlon, nlat). Wind, in m s-1.
+
+  type(snapshot) s
+
+  real, allocatable:: coord(:, :)
+  ! (2, number_extr) longitude and latitude, in rad
+
+  integer, allocatable:: selection(:)
+  ! identifying numbers of a selection of eddies
+
+  logical, allocatable:: in_window(:)
+
+  real, allocatable:: outside_points(:, :) ! (2, :) longitude and
+  ! latitude, in rad, of all the significant extrema, except the
+  ! target extremum
+
+  TYPE(shpc_slice_handler) hshpc
+  integer llc(2) ! indices in global grid of lower left corner
+  integer urc(2) ! indices in global grid of upper right corner
+
+  real corner_window(2) ! longitude and latitude of the window around each
+  ! extremum, in rad
+
+  !------------------------------------------------------------------------
+
+  call config
+  call input_ssh(corner, step, periodic, ssh, u, v)
+  call get_command_arg_dyn(3, slice_dir, &
+       "Required 3rd argument: input-slice-directory")
+  write(unit = *, nml = main_nml)
+  print *, "examine_eddy: Enter main_nml:"
+  read(unit = *, nml = main_nml)
+  write(unit = *, nml = main_nml)
+
+  if (cyclone) then
+     slice_o_dir = slice_dir // "/Cyclones"
+  else
+     slice_o_dir = slice_dir // "/Anticyclones"
+  end if
+
+  call shp_open_03(hshp, pszshapefile = slice_o_dir // "/extremum", &
+       pszaccess = "rb")
+  call dbf_get_field_index_03(hshp, "date", extr_date)
+  call dbf_read_attribute_03(d0, hshp, extr_date, ishape = 0)
+  call read_column(ishape_last, file = slice_o_dir // "/ishape_last.txt", &
+       my_lbound = d0)
+
+  if (date == d0) then
+     ishape_first = 0
+  else
+     ishape_first = ishape_last(date - 1) + 1
+  end if
+
+  number_extr = ishape_last(date) - ishape_first + 1
+  allocate(coord(2, number_extr), in_window(number_extr))
+
+  do ishape = ishape_first, ishape_last(date)
+     call shp_read_point(coord(:, ishape - ishape_first + 1), hshp, ishape)
+  end do
+
+  coord = coord * deg_to_rad
+  e%extr%coord = coord(:, eddy_i_target)
+  e%extr%coord_proj = nint(convert_to_ind(e%extr%coord, corner, step))
+  e%extr%ssh = missing_ssh ! because we do not care about this
+  e%cyclone = cyclone
+
+  ! Define the geographical window around the target eddy extremum:
+
+  llc = e%extr%coord_proj - max_radius
+  urc = e%extr%coord_proj + max_radius
+
+  llc(2) = max(llc(2), 1)
+  urc(2) = min(urc(2), size(ssh, 2))
+
+  if (.not. periodic) then
+     llc(1) = max(llc(1), 1)
+     urc(1) = min(urc(1), size(ssh, 1))
+  end if
+
+  corner_window = corner + (llc - 1) * step
+
+  ! Done defining geographical window
+
+  do i = 1, number_extr
+     if (i /= eddy_i_target) then
+        ! Shift the longitude to a value close to the longitude of the
+        ! target extremum:
+        if (periodic) coord(1, i) = coord(1, i) &
+             + ceiling((corner_window(1) - coord(1, i)) / twopi) * twopi
+
+        in_window(i) = all(abs(nint((coord(:, i) - e%extr%coord) / step)) &
+             < max_radius)
+     else
+        in_window(i) = .false.
+     end if
+  end do
+
+  n2 = count(in_window)
+  call set_all_extr(s, step, periodic = .false., &
+       ssh = ssh(llc(1):urc(1), llc(2):urc(2)), corner = corner_window)
+  selection = pack(s%extr_map, s%extr_map /= 0)
+  selection = pack(selection, s%list(selection)%cyclone .neqv. cyclone)
+  n1 = size(selection)
+  allocate(outside_points(2, n1 + n2))
+  forall (i = 1:n1) outside_points(:, i) = s%list(selection(i))%extr%coord
+  l = n1 + 1
+
+  do i = 1, number_extr
+     if (in_window(i)) then
+        outside_points(:, l) = coord(:, i)
+        l = l + 1
+     end if
+  end do
+
+  i = s%extr_map(e%extr%coord_proj(1) - llc(1) + 1, &
+       e%extr%coord_proj(2) - llc(2) + 1)
+  e%innermost_level = s%list(i)%innermost_level
+  call create_cont_list
+  call set_contours(e%out_cont, e%speed_cont, e%max_speed, cyclone, e%extr, &
+       e%innermost_level, step, ssh(llc(1):urc(1), llc(2):urc(2)), &
+       u(llc(1):urc(1), llc(2):urc(2)), v(llc(1):urc(1), llc(2):urc(2)), &
+       corner_window, pi * (min_radius * 1e3)**2, outside_points)
+  call close_cont_list
+  call shpc_create(hshpc, shpc_dir = "SHPC", cyclone = cyclone, slice = 0, &
+       grid_lon_lat = .true.)
+  call write_eddy(e, hshpc, date, 1)
+  write(hshpc%unit, fmt = *) 0
+  CALL shpc_close(hshpc)
+  print *, "llc = ", llc
+  print *, "urc = ", urc
+  print *, "corner_window (in degrees):", corner_window * rad_to_deg
+  print *, "n1 = ", n1
+  print *, "n2 = ", n2
+  print *, "outside_points = ", outside_points
+  print *, "e%innermost_level = ", e%innermost_level
+  print *, "Created shapefile cont_list and shapefile collection SHPC."
+
+end program examine_eddy
-- 
GitLab