remap_layer_to_density_impl Subroutine

private pure subroutine remap_layer_to_density_impl(h_layer, hT, hS, eos, rho_ref_p, rho_tgt, layer_buf, output_buf, is_extensive, method)

Per-column density-space remap, do concurrent over (j, i). Source column TOP-DOWN + layer potential density (EOS at rho_ref_p), invert profile to interface depths (invert_density_targets), then donor-cell remap. Cells outside the column density range read 0. Intensive/extensive as the z-remap.

Vanished source layers carry zero weight exactly as in remap_layer_to_vcoord_impl (dz = 0, q = 0, value never read), and take the density of the nearest LIVE layer (the one above, else the first one below) rather than an EOS evaluation of the filler: the EOS substitutes reference T/S on a vanished layer, and the PPM edge between a live layer and a zero-thickness neighbour IS that neighbour’s density (invert_density_targets), so a rho_0 filler would kink the profile the targets are inverted against. A column with no vanished layer is bit-identical; a column with no live layer keeps the legacy eos(0, 0) fill.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: h_layer(:,:,:)
real(kind=wp), intent(in) :: hT(:,:,:)
real(kind=wp), intent(in) :: hS(:,:,:)
type(eos_t), intent(in) :: eos
real(kind=wp), intent(in) :: rho_ref_p
real(kind=wp), intent(in) :: rho_tgt(:)
real(kind=wp), intent(in) :: layer_buf(:,:,:)
real(kind=wp), intent(inout) :: output_buf(:,:,:)
logical, intent(in) :: is_extensive
integer, intent(in) :: method

Calls

proc~~remap_layer_to_density_impl~~CallsGraph proc~remap_layer_to_density_impl remap_layer_to_density_impl local local proc~remap_layer_to_density_impl->local proc~eos_density_point eos_density_point proc~remap_layer_to_density_impl->proc~eos_density_point proc~invert_density_targets invert_density_targets proc~remap_layer_to_density_impl->proc~invert_density_targets proc~remap_column remap_column proc~remap_layer_to_density_impl->proc~remap_column rdb_vl_conc rdb_vl_conc proc~remap_layer_to_density_impl->rdb_vl_conc rdb_vl_is_live rdb_vl_is_live proc~remap_layer_to_density_impl->rdb_vl_is_live proc~roquet_spv_value roquet_spv_value proc~eos_density_point->proc~roquet_spv_value proc~remap_column_pcm remap_column_pcm proc~remap_column->proc~remap_column_pcm proc~remap_column_plm remap_column_plm proc~remap_column->proc~remap_column_plm proc~remap_column_ppm remap_column_ppm proc~remap_column->proc~remap_column_ppm proc~remap_column_ppm_h4 remap_column_ppm_h4 proc~remap_column->proc~remap_column_ppm_h4 proc~remap_column_pqm remap_column_pqm proc~remap_column->proc~remap_column_pqm proc~boundary_half_jump boundary_half_jump proc~remap_column_plm->proc~boundary_half_jump proc~plm_slope_nonuniform plm_slope_nonuniform proc~remap_column_plm->proc~plm_slope_nonuniform proc~remap_column_ppm->proc~remap_column_plm proc~remap_column_ppm->proc~boundary_half_jump proc~ppm_edge_nonuniform ppm_edge_nonuniform proc~remap_column_ppm->proc~ppm_edge_nonuniform proc~ppm_edge_two_cell ppm_edge_two_cell proc~remap_column_ppm->proc~ppm_edge_two_cell proc~ppm_jump_nonuniform ppm_jump_nonuniform proc~remap_column_ppm->proc~ppm_jump_nonuniform proc~remap_column_ppm_h4->proc~remap_column_plm proc~remap_column_ppm_h4->proc~boundary_half_jump proc~remap_column_pqm->proc~remap_column_ppm proc~remap_column_pqm->proc~boundary_half_jump proc~pqm_end_value_h4 pqm_end_value_h4 proc~remap_column_pqm->proc~pqm_end_value_h4 proc~pqm_solve_diag_dominant pqm_solve_diag_dominant proc~remap_column_pqm->proc~pqm_solve_diag_dominant rdb_roq_spv_p rdb_roq_spv_p proc~roquet_spv_value->rdb_roq_spv_p rdb_roq_ts_coeffs rdb_roq_ts_coeffs proc~roquet_spv_value->rdb_roq_ts_coeffs

Called by

proc~~remap_layer_to_density_impl~~CalledByGraph proc~remap_layer_to_density_impl remap_layer_to_density_impl proc~remap_layer_to_density remap_layer_to_density proc~remap_layer_to_density->proc~remap_layer_to_density_impl

Variables

Type Visibility Attributes Name Initial
real(kind=wp), private :: dz_new(NZ_STACK_MAX)
real(kind=wp), private :: dz_old(NZ_STACK_MAX)
real(kind=wp), private :: hh
integer, private :: i
integer, private :: j
integer, private :: k
integer, private :: m
integer, private :: n
integer, private :: n_bin
integer, private :: nx
integer, private :: ny
integer, private :: nz
real(kind=wp), private :: q_new(NZ_STACK_MAX)
real(kind=wp), private :: q_old(NZ_STACK_MAX)
real(kind=wp), private :: rho_live
real(kind=wp), private :: rho_tgt_c(NZ_STACK_MAX)
real(kind=wp), private :: rhoc(NZ_STACK_MAX)
logical, private :: seen_live
real(kind=wp), private :: ss
real(kind=wp), private :: tt
real(kind=wp), private :: z_iface(NZ_STACK_MAX+2)

Source Code

   pure subroutine remap_layer_to_density_impl(h_layer, hT, hS, eos, rho_ref_p, &
                                               rho_tgt, layer_buf, output_buf, &
                                               is_extensive, method)
      !! Per-column density-space remap, `do concurrent` over (j, i).
      !! Source column TOP-DOWN + layer potential density (EOS at
      !! `rho_ref_p`), invert profile to interface depths
      !! (`invert_density_targets`), then donor-cell remap.  Cells outside
      !! the column density range read 0.  Intensive/extensive as the z-remap.
      !!
      !! **Vanished source layers** carry zero weight exactly as in
      !! `remap_layer_to_vcoord_impl` (`dz = 0`, `q = 0`, value never read),
      !! and take the density of the nearest LIVE layer (the one above,
      !! else the first one below) rather than an EOS evaluation of the
      !! filler: the EOS substitutes reference T/S on a vanished layer, and
      !! the PPM edge between a live layer and a zero-thickness neighbour IS
      !! that neighbour's density (`invert_density_targets`), so a `rho_0`
      !! filler would kink the profile the targets are inverted against.
      !! A column with no vanished layer is bit-identical; a column with no
      !! live layer keeps the legacy `eos(0, 0)` fill.
      ! assumed-shape-ok: diag fill — fires once per output frame (cadence-bounded);
      ! size() used to derive loop bounds from the actual buffer dimensions.
      real(wp), intent(in)    :: h_layer(:, :, :)
      real(wp), intent(in)    :: hT(:, :, :)  ! assumed-shape-ok: diag fill — cadence-bounded
      real(wp), intent(in)    :: hS(:, :, :)  ! assumed-shape-ok: diag fill — cadence-bounded
      type(eos_t), intent(in) :: eos
      real(wp), intent(in)    :: rho_ref_p
      real(wp), intent(in)    :: rho_tgt(:)  ! assumed-shape-ok: diag fill — cadence-bounded
      real(wp), intent(in)    :: layer_buf(:, :, :)  ! assumed-shape-ok: diag fill — cadence-bounded
      real(wp), intent(inout) :: output_buf(:, :, :)
      logical, intent(in)    :: is_extensive
      integer, intent(in)    :: method
      integer :: i, j, k, m, nx, ny, nz, n_bin, n
      real(wp) :: dz_old(NZ_STACK_MAX), dz_new(NZ_STACK_MAX)
      real(wp) :: q_old(NZ_STACK_MAX), q_new(NZ_STACK_MAX)
      ! z_iface holds n_bin+2 entries (`invert_density_targets` writes
      ! z_new(1:n_int+2) with n_int = n_bin, and :798 reads z_iface(n_bin+2)),
      ! so it needs NZ_STACK_MAX+2 — at NZ_STACK_MAX+1 a density diagnostic
      ! with n_rho_out == NZ_STACK_MAX (which the output-level guard permits)
      ! wrote and read one element past the end.
      real(wp) :: rhoc(NZ_STACK_MAX), z_iface(NZ_STACK_MAX + 2)
      real(wp) :: rho_tgt_c(NZ_STACK_MAX)
      real(wp) :: hh, tt, ss, rho_live
      logical :: seen_live
      nx = size(layer_buf, 1)
      ny = size(layer_buf, 2)
      nz = size(layer_buf, 3)
      n_bin = size(rho_tgt)      ! number of density bins (output cells)
      n = max(nz, n_bin)
      do concurrent(j=1:ny, i=1:nx) &
         local(dz_old, dz_new, q_old, q_new, rhoc, z_iface, rho_tgt_c, &
               k, m, hh, tt, ss, rho_live, seen_live)
         ! --- source column TOP-DOWN + layer potential density ---
         ! Vanished layers: zero weight, density of the nearest live layer
         ! (see the docstring).
         seen_live = .false.
         rho_live = 0.0_wp
         do k = 1, nz
            hh = h_layer(i, j, nz - k + 1)
            if (rdb_vl_is_live(hh)) then
               dz_old(k) = hh
               q_old(k) = layer_buf(i, j, nz - k + 1)
               tt = rdb_vl_conc(hT(i, j, nz - k + 1), hh)
               ss = rdb_vl_conc(hS(i, j, nz - k + 1), hh)
               rhoc(k) = eos_density_point(eos, tt, ss, rho_ref_p)
               if (.not. seen_live) then
                  ! Back-fill the vanished run above the first live layer.
                  do m = 1, k - 1
                     rhoc(m) = rhoc(k)
                  end do
               end if
               seen_live = .true.
               rho_live = rhoc(k)
            else
               dz_old(k) = 0.0_wp
               q_old(k) = 0.0_wp
               if (seen_live) then
                  rhoc(k) = rho_live
               else
                  rhoc(k) = eos_density_point(eos, 0.0_wp, 0.0_wp, rho_ref_p)
               end if
            end if
         end do
         if (is_extensive) then
            do k = 1, nz
               if (dz_old(k) > 1.0e-12_wp) then
                  q_old(k) = q_old(k)/dz_old(k)
               else
                  q_old(k) = 0.0_wp
               end if
            end do
         end if
         do k = nz + 1, n
            dz_old(k) = 0.0_wp
            q_old(k) = 0.0_wp
         end do
         ! --- invert instantaneous density to target-interface depths ---
         ! n_bin output cells; the LAST cell absorbs to the bed so
         ! Σ dz_new == H exactly (extensive conservation, densest mass kept).
         ! Copy assumed-shape rho_tgt(:) into a contiguous fixed-size local
         ! first: passing the assumed-shape actual to the explicit-shape
         ! dummy makes flang emit host copy helpers absent in the AMD device
         ! runtime → offload link fails.  Element reads off the descriptor OK.
         do m = 1, n_bin
            rho_tgt_c(m) = rho_tgt(m)
         end do
         call invert_density_targets(nz, dz_old, rhoc, n_bin, rho_tgt_c, z_iface)
         do m = 1, n_bin - 1
            dz_new(m) = z_iface(m + 1) - z_iface(m)
            if (dz_new(m) < 0.0_wp) dz_new(m) = 0.0_wp
         end do
         dz_new(n_bin) = z_iface(n_bin + 2) - z_iface(n_bin)
         if (dz_new(n_bin) < 0.0_wp) dz_new(n_bin) = 0.0_wp
         do m = n_bin + 1, n
            dz_new(m) = 0.0_wp
         end do
         call remap_column(method, n, dz_old, dz_new, q_old, q_new)
         do m = 1, n_bin
            if (is_extensive) then
               output_buf(i, j, m) = q_new(m)*dz_new(m)
            else
               output_buf(i, j, m) = q_new(m)
            end if
         end do
      end do
   end subroutine remap_layer_to_density_impl