25 use mom_io,
only : create_file, write_field, close_file
29 use mom_regridding,
only : initialize_regridding, regridding_main, end_regridding
32 use mom_regridding,
only : set_target_densities_from_gv, set_target_densities
33 use mom_regridding,
only : regriddingcoordinatemodedoc, default_coordinate_mode
34 use mom_regridding,
only : regriddinginterpschemedoc, regriddingdefaultinterpscheme
38 use mom_regridding,
only : getcoordinateinterfaces, getcoordinateresolution
39 use mom_regridding,
only : getcoordinateunits, getcoordinateshortname
43 use mom_remapping,
only : remappingschemesdoc, remappingdefaultscheme
54 use plm_functions,
only : plm_reconstruction, plm_boundary_extrapolation
55 use plm_functions,
only : plm_extrapolate_slope, plm_monotonized_slope, plm_slope_wa
56 use ppm_functions,
only : ppm_reconstruction, ppm_boundary_extrapolation
58 implicit none ;
private
59 #include <MOM_memory.h>
64 logical :: remap_uv_using_old_alg
68 real :: regrid_time_scale
76 logical :: remap_after_initialization
78 logical :: answers_2018
82 logical :: show_call_tree
86 integer,
dimension(:),
allocatable :: id_tracer_remap_tendency
87 integer,
dimension(:),
allocatable :: id_htracer_remap_tendency
88 integer,
dimension(:),
allocatable :: id_htracer_remap_tendency_2d
89 logical,
dimension(:),
allocatable :: do_tendency_diag
90 integer :: id_dzregrid = -1
93 integer :: id_u_preale = -1
94 integer :: id_v_preale = -1
95 integer :: id_h_preale = -1
96 integer :: id_t_preale = -1
97 integer :: id_s_preale = -1
98 integer :: id_e_preale = -1
99 integer :: id_vert_remap_h = -1
100 integer :: id_vert_remap_h_tendency = -1
108 public ale_main_offline
109 public ale_offline_inputs
110 public ale_offline_tracer_final
111 public ale_build_grid
112 public ale_regrid_accelerated
113 public ale_remap_scalar
114 public ale_plm_edge_values
115 public ts_plm_edge_values
116 public ts_ppm_edge_values
117 public adjustgridforintegrity
118 public ale_initregridding
119 public ale_getcoordinate
120 public ale_getcoordinateunits
121 public ale_writecoordinatefile
122 public ale_updateverticalgridtype
123 public ale_initthicknesstocoord
124 public ale_update_regrid_weights
125 public ale_remap_init_conds
126 public ale_register_diags
139 subroutine ale_init( param_file, GV, US, max_depth, CS)
143 real,
intent(in) :: max_depth
144 type(
ale_cs),
pointer :: cs
147 real,
dimension(:),
allocatable :: dz
148 character(len=40) :: mdl =
"MOM_ALE"
149 character(len=80) :: string
150 real :: filter_shallow_depth, filter_deep_depth
151 logical :: default_2018_answers
152 logical :: check_reconstruction
153 logical :: check_remapping
154 logical :: force_bounds_in_subcell
155 logical :: local_logical
156 logical :: remap_boundary_extrap
158 if (
associated(cs))
then
159 call mom_error(warning,
"ALE_init called with an associated "// &
160 "control structure.")
165 cs%show_call_tree = calltree_showquery()
166 if (cs%show_call_tree)
call calltree_enter(
"ALE_init(), MOM_ALE.F90")
168 call get_param(param_file, mdl,
"REMAP_UV_USING_OLD_ALG", cs%remap_uv_using_old_alg, &
169 "If true, uses the old remapping-via-a-delta-z method for "//&
170 "remapping u and v. If false, uses the new method that remaps "//&
171 "between grids described by an old and new thickness.", &
175 call ale_initregridding(gv, us, max_depth, param_file, mdl, cs%regridCS)
178 call get_param(param_file, mdl,
"REMAPPING_SCHEME", string, &
179 "This sets the reconstruction scheme used "//&
180 "for vertical remapping for all variables. "//&
181 "It can be one of the following schemes: "//&
182 trim(remappingschemesdoc), default=remappingdefaultscheme)
183 call get_param(param_file, mdl,
"FATAL_CHECK_RECONSTRUCTIONS", check_reconstruction, &
184 "If true, cell-by-cell reconstructions are checked for "//&
185 "consistency and if non-monotonicity or an inconsistency is "//&
186 "detected then a FATAL error is issued.", default=.false.)
187 call get_param(param_file, mdl,
"FATAL_CHECK_REMAPPING", check_remapping, &
188 "If true, the results of remapping are checked for "//&
189 "conservation and new extrema and if an inconsistency is "//&
190 "detected then a FATAL error is issued.", default=.false.)
191 call get_param(param_file, mdl,
"REMAP_BOUND_INTERMEDIATE_VALUES", force_bounds_in_subcell, &
192 "If true, the values on the intermediate grid used for remapping "//&
193 "are forced to be bounded, which might not be the case due to "//&
194 "round off.", default=.false.)
195 call get_param(param_file, mdl,
"REMAP_BOUNDARY_EXTRAP", remap_boundary_extrap, &
196 "If true, values at the interfaces of boundary cells are "//&
197 "extrapolated instead of piecewise constant", default=.false.)
198 call get_param(param_file, mdl,
"DEFAULT_2018_ANSWERS", default_2018_answers, &
199 "This sets the default value for the various _2018_ANSWERS parameters.", &
201 call get_param(param_file, mdl,
"REMAPPING_2018_ANSWERS", cs%answers_2018, &
202 "If true, use the order of arithmetic and expressions that recover the "//&
203 "answers from the end of 2018. Otherwise, use updated and more robust "//&
204 "forms of the same expressions.", default=default_2018_answers)
205 call initialize_remapping( cs%remapCS, string, &
206 boundary_extrapolation=remap_boundary_extrap, &
207 check_reconstruction=check_reconstruction, &
208 check_remapping=check_remapping, &
209 force_bounds_in_subcell=force_bounds_in_subcell, &
210 answers_2018=cs%answers_2018)
212 call get_param(param_file, mdl,
"REMAP_AFTER_INITIALIZATION", cs%remap_after_initialization, &
213 "If true, applies regridding and remapping immediately after "//&
214 "initialization so that the state is ALE consistent. This is a "//&
215 "legacy step and should not be needed if the initialization is "//&
216 "consistent with the coordinate mode.", default=.true.)
218 call get_param(param_file, mdl,
"REGRID_TIME_SCALE", cs%regrid_time_scale, &
219 "The time-scale used in blending between the current (old) grid "//&
220 "and the target (new) grid. A short time-scale favors the target "//&
221 "grid (0. or anything less than DT_THERM) has no memory of the old "//&
222 "grid. A very long time-scale makes the model more Lagrangian.", &
223 units=
"s", default=0., scale=us%s_to_T)
224 call get_param(param_file, mdl,
"REGRID_FILTER_SHALLOW_DEPTH", filter_shallow_depth, &
225 "The depth above which no time-filtering is applied. Above this depth "//&
226 "final grid exactly matches the target (new) grid.", &
227 units=
"m", default=0., scale=gv%m_to_H)
228 call get_param(param_file, mdl,
"REGRID_FILTER_DEEP_DEPTH", filter_deep_depth, &
229 "The depth below which full time-filtering is applied with time-scale "//&
230 "REGRID_TIME_SCALE. Between depths REGRID_FILTER_SHALLOW_DEPTH and "//&
231 "REGRID_FILTER_SHALLOW_DEPTH the filter weights adopt a cubic profile.", &
232 units=
"m", default=0., scale=gv%m_to_H)
233 call set_regrid_params(cs%regridCS, depth_of_time_filter_shallow=filter_shallow_depth, &
234 depth_of_time_filter_deep=filter_deep_depth)
235 call get_param(param_file, mdl,
"REGRID_USE_OLD_DIRECTION", local_logical, &
236 "If true, the regridding ntegrates upwards from the bottom for "//&
237 "interface positions, much as the main model does. If false "//&
238 "regridding integrates downward, consistant with the remapping "//&
239 "code.", default=.true., do_not_log=.true.)
240 call set_regrid_params(cs%regridCS, integrate_downward_for_e=.not.local_logical)
245 if (cs%show_call_tree)
call calltree_leave(
"ALE_init()")
246 end subroutine ale_init
249 subroutine ale_register_diags(Time, G, GV, US, diag, CS)
250 type(time_type),
target,
intent(in) :: time
251 type(ocean_grid_type),
intent(in) :: g
254 type(
diag_ctrl),
target,
intent(in) :: diag
255 type(
ale_cs),
pointer :: cs
261 cs%id_u_preale = register_diag_field(
'ocean_model',
'u_preale', diag%axesCuL, time, &
262 'Zonal velocity before remapping',
'm s-1', conversion=us%L_T_to_m_s)
263 cs%id_v_preale = register_diag_field(
'ocean_model',
'v_preale', diag%axesCvL, time, &
264 'Meridional velocity before remapping',
'm s-1', conversion=us%L_T_to_m_s)
265 cs%id_h_preale = register_diag_field(
'ocean_model',
'h_preale', diag%axesTL, time, &
266 'Layer Thickness before remapping', get_thickness_units(gv), &
267 conversion=gv%H_to_MKS, v_extensive=.true.)
268 cs%id_T_preale = register_diag_field(
'ocean_model',
'T_preale', diag%axesTL, time, &
269 'Temperature before remapping',
'degC')
270 cs%id_S_preale = register_diag_field(
'ocean_model',
'S_preale', diag%axesTL, time, &
271 'Salinity before remapping',
'PSU')
272 cs%id_e_preale = register_diag_field(
'ocean_model',
'e_preale', diag%axesTi, time, &
273 'Interface Heights before remapping',
'm', conversion=us%Z_to_m)
275 cs%id_dzRegrid = register_diag_field(
'ocean_model',
'dzRegrid',diag%axesTi,time, &
276 'Change in interface height due to ALE regridding',
'm', &
277 conversion=gv%H_to_m)
278 cs%id_vert_remap_h = register_diag_field(
'ocean_model',
'vert_remap_h', &
279 diag%axestl, time,
'layer thicknesses after ALE regridding and remapping',
'm', &
280 conversion=gv%H_to_m, v_extensive=.true.)
281 cs%id_vert_remap_h_tendency = register_diag_field(
'ocean_model',
'vert_remap_h_tendency',diag%axestl,time, &
282 'Layer thicknesses tendency due to ALE regridding and remapping',
'm', &
283 conversion=gv%H_to_m*us%s_to_T, v_extensive = .true.)
285 end subroutine ale_register_diags
292 subroutine adjustgridforintegrity( CS, G, GV, h )
294 type(ocean_grid_type),
intent(in) :: g
296 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: h
298 call inflate_vanished_layers_old( cs%regridCS, g, gv, h(:,:,:) )
300 end subroutine adjustgridforintegrity
306 subroutine ale_end(CS)
310 call end_remapping( cs%remapCS )
311 call end_regridding( cs%regridCS )
315 end subroutine ale_end
321 subroutine ale_main( G, GV, US, h, u, v, tv, Reg, CS, OBC, dt, frac_shelf_h)
322 type(ocean_grid_type),
intent(in) :: g
325 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: h
327 real,
dimension(SZIB_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: u
328 real,
dimension(SZI_(G),SZJB_(G),SZK_(GV)),
intent(inout) :: v
331 type(
ale_cs),
pointer :: cs
333 real,
optional,
intent(in) :: dt
334 real,
dimension(:,:),
optional,
pointer :: frac_shelf_h
336 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: dzregrid
337 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: eta_preale
338 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_new
339 integer :: nk, i, j, k, isc, iec, jsc, jec
342 nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
345 if (
present(frac_shelf_h))
then
346 if (
associated(frac_shelf_h)) ice_shelf = .true.
349 if (cs%show_call_tree)
call calltree_enter(
"ALE_main(), MOM_ALE.F90")
352 if (cs%id_u_preale > 0)
call post_data(cs%id_u_preale, u, cs%diag)
353 if (cs%id_v_preale > 0)
call post_data(cs%id_v_preale, v, cs%diag)
354 if (cs%id_h_preale > 0)
call post_data(cs%id_h_preale, h, cs%diag)
355 if (cs%id_T_preale > 0)
call post_data(cs%id_T_preale, tv%T, cs%diag)
356 if (cs%id_S_preale > 0)
call post_data(cs%id_S_preale, tv%S, cs%diag)
357 if (cs%id_e_preale > 0)
then
358 call find_eta(h, tv, g, gv, us, eta_preale)
359 call post_data(cs%id_e_preale, eta_preale, cs%diag)
362 if (
present(dt))
then
363 call ale_update_regrid_weights( dt, cs )
365 dzregrid(:,:,:) = 0.0
370 call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid, frac_shelf_h)
372 call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid)
375 call check_grid( g, gv, h, 0. )
377 if (cs%show_call_tree)
call calltree_waypoint(
"new grid generated (ALE_main)")
381 if (
present(dt))
then
382 call diag_update_remap_grids(cs%diag)
385 call remap_all_state_vars( cs%remapCS, cs, g, gv, h, h_new, reg, obc, -dzregrid, &
386 u, v, cs%show_call_tree, dt )
388 if (cs%show_call_tree)
call calltree_waypoint(
"state remapped (ALE_main)")
393 do k = 1,nk ;
do j = jsc-1,jec+1 ;
do i = isc-1,iec+1
394 h(i,j,k) = h_new(i,j,k)
395 enddo ;
enddo ;
enddo
397 if (cs%show_call_tree)
call calltree_leave(
"ALE_main()")
399 if (cs%id_dzRegrid>0 .and.
present(dt))
call post_data(cs%id_dzRegrid, dzregrid, cs%diag)
402 end subroutine ale_main
408 subroutine ale_main_offline( G, GV, h, tv, Reg, CS, OBC, dt)
409 type(ocean_grid_type),
intent(in) :: g
411 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: h
415 type(
ale_cs),
pointer :: cs
417 real,
optional,
intent(in) :: dt
419 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid
420 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_new
421 integer :: nk, i, j, k, isc, iec, jsc, jec
423 nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
425 if (cs%show_call_tree)
call calltree_enter(
"ALE_main_offline(), MOM_ALE.F90")
427 if (
present(dt))
then
428 call ale_update_regrid_weights( dt, cs )
430 dzregrid(:,:,:) = 0.0
434 call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid )
436 call check_grid( g, gv, h, 0. )
438 if (cs%show_call_tree)
call calltree_waypoint(
"new grid generated (ALE_main)")
442 call remap_all_state_vars(cs%remapCS, cs, g, gv, h, h_new, reg, obc, &
443 debug=cs%show_call_tree, dt=dt )
445 if (cs%show_call_tree)
call calltree_waypoint(
"state remapped (ALE_main)")
450 do k = 1,nk ;
do j = jsc-1,jec+1 ;
do i = isc-1,iec+1
451 h(i,j,k) = h_new(i,j,k)
452 enddo ;
enddo ;
enddo
454 if (cs%show_call_tree)
call calltree_leave(
"ALE_main()")
455 if (cs%id_dzRegrid>0 .and.
present(dt))
call post_data(cs%id_dzRegrid, dzregrid, cs%diag)
457 end subroutine ale_main_offline
462 subroutine ale_offline_inputs(CS, G, GV, h, tv, Reg, uhtr, vhtr, Kd, debug, OBC)
464 type(ocean_grid_type),
intent(in ) :: g
466 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: h
469 real,
dimension(SZIB_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: uhtr
470 real,
dimension(SZI_(G),SZJB_(G),SZK_(GV)),
intent(inout) :: vhtr
471 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)+1),
intent(inout) :: kd
472 logical,
intent(in ) :: debug
475 integer :: nk, i, j, k, isc, iec, jsc, jec
476 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: h_new
477 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid
478 real,
dimension(SZK_(GV)) :: h_src
479 real,
dimension(SZK_(GV)) :: h_dest, uh_dest
480 real,
dimension(SZK_(GV)) :: temp_vec
482 nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
483 dzregrid(:,:,:) = 0.0
486 if (debug)
call mom_tracer_chkinv(
"Before ALE_offline_inputs", g, h, reg%Tr, reg%ntr)
491 call regridding_main( cs%remapCS, cs%regridCS, g, gv, h, tv, h_new, dzregrid, conv_adjust = .false. )
492 call check_grid( g, gv, h_new, 0. )
493 if (cs%show_call_tree)
call calltree_waypoint(
"new grid generated (ALE_offline_inputs)")
496 call remap_all_state_vars( cs%remapCS, cs, g, gv, h, h_new, reg, obc, debug=cs%show_call_tree )
497 if (cs%show_call_tree)
call calltree_waypoint(
"state remapped (ALE_inputs)")
500 do j=jsc,jec ;
do i=g%iscB,g%iecB
501 if (g%mask2dCu(i,j)>0.)
then
502 h_src(:) = 0.5 * (h(i,j,:) + h(i+1,j,:))
503 h_dest(:) = 0.5 * (h_new(i,j,:) + h_new(i+1,j,:))
504 call reintegrate_column(nk, h_src, uhtr(i,j,:), nk, h_dest, 0., temp_vec)
505 uhtr(i,j,:) = temp_vec
508 do j=g%jscB,g%jecB ;
do i=isc,iec
509 if (g%mask2dCv(i,j)>0.)
then
510 h_src(:) = 0.5 * (h(i,j,:) + h(i,j+1,:))
511 h_dest(:) = 0.5 * (h_new(i,j,:) + h_new(i,j+1,:))
512 call reintegrate_column(nk, h_src, vhtr(i,j,:), nk, h_dest, 0., temp_vec)
513 vhtr(i,j,:) = temp_vec
517 do j = jsc,jec ;
do i=isc,iec
518 if (g%mask2dT(i,j)>0.)
then
519 if (check_column_integrals(nk, h_src, nk, h_dest))
then
520 call mom_error(fatal,
"ALE_offline_inputs: Kd interpolation columns do not match")
522 call interpolate_column(nk, h(i,j,:), kd(i,j,:), nk, h_new(i,j,:), 0., kd(i,j,:))
526 call ale_remap_scalar(cs%remapCS, g, gv, nk, h, tv%T, h_new, tv%T, answers_2018=cs%answers_2018)
527 call ale_remap_scalar(cs%remapCS, g, gv, nk, h, tv%S, h_new, tv%S, answers_2018=cs%answers_2018)
529 if (debug)
call mom_tracer_chkinv(
"After ALE_offline_inputs", g, h_new, reg%Tr, reg%ntr)
532 do k = 1,nk ;
do j = jsc-1,jec+1 ;
do i = isc-1,iec+1
533 h(i,j,k) = h_new(i,j,k)
534 enddo ;
enddo ;
enddo
536 if (cs%show_call_tree)
call calltree_leave(
"ALE_offline_inputs()")
537 end subroutine ale_offline_inputs
543 subroutine ale_offline_tracer_final( G, GV, h, tv, h_target, Reg, CS, OBC)
544 type(ocean_grid_type),
intent(in) :: g
546 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: h
549 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: h_target
552 type(
ale_cs),
pointer :: cs
556 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid
557 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: h_new
558 integer :: nk, i, j, k, isc, iec, jsc, jec
560 nk = gv%ke; isc = g%isc; iec = g%iec; jsc = g%jsc; jec = g%jec
562 if (cs%show_call_tree)
call calltree_enter(
"ALE_offline_tracer_final(), MOM_ALE.F90")
564 call regridding_main( cs%remapCS, cs%regridCS, g, gv, h_target, tv, h_new, dzregrid )
565 call check_grid( g, gv, h_target, 0. )
568 if (cs%show_call_tree)
call calltree_waypoint(
"Source and target grids checked (ALE_offline_tracer_final)")
572 call remap_all_state_vars( cs%remapCS, cs, g, gv, h, h_new, reg, obc, debug=cs%show_call_tree )
574 if (cs%show_call_tree)
call calltree_waypoint(
"state remapped (ALE_offline_tracer_final)")
580 do j = jsc-1,jec+1 ;
do i = isc-1,iec+1
581 h(i,j,k) = h_new(i,j,k)
584 if (cs%show_call_tree)
call calltree_leave(
"ALE_offline_tracer_final()")
585 end subroutine ale_offline_tracer_final
588 subroutine check_grid( G, GV, h, threshold )
589 type(ocean_grid_type),
intent(in) :: G
591 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: h
593 real,
intent(in) :: threshold
598 do j = g%jsc,g%jec ;
do i = g%isc,g%iec
599 if (g%mask2dT(i,j)>0.)
then
600 if (minval(h(i,j,:)) < threshold)
then
601 write(0,*)
'check_grid: i,j=',i,j,
'h(i,j,:)=',h(i,j,:)
602 if (threshold <= 0.)
then
603 call mom_error(fatal,
"MOM_ALE, check_grid: negative thickness encountered.")
605 call mom_error(fatal,
"MOM_ALE, check_grid: too tiny thickness encountered.")
612 end subroutine check_grid
615 subroutine ale_build_grid( G, GV, regridCS, remapCS, h, tv, debug, frac_shelf_h )
616 type(ocean_grid_type),
intent(in) :: g
621 real,
dimension(SZI_(G),SZJ_(G), SZK_(GV)),
intent(inout) :: h
623 logical,
optional,
intent(in) :: debug
624 real,
dimension(:,:),
optional,
pointer :: frac_shelf_h
626 integer :: nk, i, j, k
627 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)+1) :: dzregrid
628 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: h_new
629 logical :: show_call_tree, use_ice_shelf
631 show_call_tree = .false.
632 if (
present(debug)) show_call_tree = debug
633 if (show_call_tree)
call calltree_enter(
"ALE_build_grid(), MOM_ALE.F90")
634 use_ice_shelf = .false.
635 if (
present(frac_shelf_h))
then
636 if (
associated(frac_shelf_h)) use_ice_shelf = .true.
641 if (use_ice_shelf)
then
642 call regridding_main( remapcs, regridcs, g, gv, h, tv, h_new, dzregrid, frac_shelf_h )
644 call regridding_main( remapcs, regridcs, g, gv, h, tv, h_new, dzregrid )
650 do j = g%jsc,g%jec ;
do i = g%isc,g%iec
651 if (g%mask2dT(i,j)>0.) h(i,j,:) = h_new(i,j,:)
654 if (show_call_tree)
call calltree_leave(
"ALE_build_grid()")
655 end subroutine ale_build_grid
659 subroutine ale_regrid_accelerated(CS, G, GV, h, tv, n, u, v, OBC, Reg, dt, dzRegrid, initial)
661 type(ocean_grid_type),
intent(inout) :: g
663 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
666 integer,
intent(in) :: n
667 real,
dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
669 real,
dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
673 optional,
pointer :: reg
674 real,
optional,
intent(in) :: dt
675 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
676 optional,
intent(inout) :: dzregrid
677 logical,
optional,
intent(in) :: initial
681 integer :: i, j, k, nz
683 type(group_pass_type) :: pass_t_s_h
684 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h_loc, h_orig
685 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
target :: t, s
688 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)+1) :: dzinterface, dzinttotal
693 dzinttotal(:,:,:) = 0.
701 t(:,:,:) = tv%T(:,:,:)
702 s(:,:,:) = tv%S(:,:,:)
707 h_loc(:,:,:) = h(:,:,:)
708 h_orig(:,:,:) = h(:,:,:)
712 call ale_update_regrid_weights(dt, cs)
715 call do_group_pass(pass_t_s_h, g%domain)
718 call regridding_main(cs%remapCS, cs%regridCS, g, gv, h_loc, tv_local, h, dzinterface)
719 dzinttotal(:,:,:) = dzinttotal(:,:,:) + dzinterface(:,:,:)
722 do j = g%jsc-1,g%jec+1 ;
do i = g%isc-1,g%iec+1
723 call remapping_core_h(cs%remapCS, nz, h_orig(i,j,:), tv%S(i,j,:), nz, h(i,j,:), tv_local%S(i,j,:))
724 call remapping_core_h(cs%remapCS, nz, h_orig(i,j,:), tv%T(i,j,:), nz, h(i,j,:), tv_local%T(i,j,:))
728 h_loc(:,:,:) = h(:,:,:)
732 call remap_all_state_vars(cs%remapCS, cs, g, gv, h_orig, h, reg, obc, dzinttotal, u, v)
735 if (
present(dzregrid)) dzregrid(:,:,:) = dzinttotal(:,:,:)
736 end subroutine ale_regrid_accelerated
744 subroutine remap_all_state_vars(CS_remapping, CS_ALE, G, GV, h_old, h_new, Reg, OBC, &
745 dxInterface, u, v, debug, dt)
747 type(
ale_cs),
intent(in) :: CS_ALE
748 type(ocean_grid_type),
intent(in) :: G
750 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: h_old
752 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: h_new
756 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), &
757 optional,
intent(in) :: dxInterface
759 real,
dimension(SZIB_(G),SZJ_(G),SZK_(GV)), &
760 optional,
intent(inout) :: u
761 real,
dimension(SZI_(G),SZJB_(G),SZK_(GV)), &
762 optional,
intent(inout) :: v
763 logical,
optional,
intent(in) :: debug
764 real,
optional,
intent(in) :: dt
766 integer :: i, j, k, m
768 real,
dimension(GV%ke+1) :: dx
769 real,
dimension(GV%ke) :: h1, u_column
770 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: work_conc
771 real,
dimension(SZI_(G), SZJ_(G), SZK_(GV)) :: work_cont
772 real,
dimension(SZI_(G), SZJ_(G)) :: work_2d
775 real,
dimension(GV%ke) :: h2
776 real :: h_neglect, h_neglect_edge
777 logical :: show_call_tree
780 show_call_tree = .false.
781 if (
present(debug)) show_call_tree = debug
782 if (show_call_tree)
call calltree_enter(
"remap_all_state_vars(), MOM_ALE.F90")
786 if ( .not.
present(dxinterface) .and. (cs_ale%remap_uv_using_old_alg .and. (
present(u) .or.
present(v))) )
then
787 call mom_error(fatal,
"remap_all_state_vars: dxInterface must be present if using old algorithm "// &
788 "and u/v are to be remapped")
791 if (.not.cs_ale%answers_2018)
then
792 h_neglect = gv%H_subroundoff ; h_neglect_edge = gv%H_subroundoff
793 elseif (gv%Boussinesq)
then
794 h_neglect = gv%m_to_H*1.0e-30 ; h_neglect_edge = gv%m_to_H*1.0e-10
796 h_neglect = gv%kg_m2_to_H*1.0e-30 ; h_neglect_edge = gv%kg_m2_to_H*1.0e-10
802 ntr = 0 ;
if (
associated(reg)) ntr = reg%ntr
804 if (
present(dt))
then
806 work_conc(:,:,:) = 0.0
807 work_cont(:,:,:) = 0.0
812 if (show_call_tree)
call calltree_waypoint(
"remapping tracers (remap_all_state_vars)")
816 do j = g%jsc,g%jec ;
do i = g%isc,g%iec ;
if (g%mask2dT(i,j)>0.)
then
820 call remapping_core_h(cs_remapping, nz, h1, tr%t(i,j,:), nz, h2, &
821 u_column, h_neglect, h_neglect_edge)
824 if (
present(dt))
then
825 if (tr%id_remap_conc > 0)
then
827 work_conc(i,j,k) = (u_column(k) - tr%t(i,j,k)) * idt
830 if (tr%id_remap_cont > 0 .or. tr%id_remap_cont_2d > 0)
then
832 work_cont(i,j,k) = (u_column(k)*h2(k) - tr%t(i,j,k)*h1(k)) * idt
837 tr%t(i,j,:) = u_column(:)
838 endif ;
enddo ;
enddo
841 if (
present(dt))
then
842 if (tr%id_remap_conc > 0)
then
843 call post_data(tr%id_remap_conc, work_conc, cs_ale%diag)
845 if (tr%id_remap_cont > 0)
then
846 call post_data(tr%id_remap_cont, work_cont, cs_ale%diag)
848 if (tr%id_remap_cont_2d > 0)
then
849 do j = g%jsc,g%jec ;
do i = g%isc,g%iec
852 work_2d(i,j) = work_2d(i,j) + work_cont(i,j,k)
855 call post_data(tr%id_remap_cont_2d, work_2d, cs_ale%diag)
862 if (show_call_tree)
call calltree_waypoint(
"tracers remapped (remap_all_state_vars)")
865 if (
present(u) )
then
867 do j = g%jsc,g%jec ;
do i = g%iscB,g%iecB ;
if (g%mask2dCu(i,j)>0.)
then
869 h1(:) = 0.5 * ( h_old(i,j,:) + h_old(i+1,j,:) )
870 if (cs_ale%remap_uv_using_old_alg)
then
871 dx(:) = 0.5 * ( dxinterface(i,j,:) + dxinterface(i+1,j,:) )
873 h2(k) = max( 0., h1(k) + ( dx(k+1) - dx(k) ) )
876 h2(:) = 0.5 * ( h_new(i,j,:) + h_new(i+1,j,:) )
878 if (
associated(obc))
then
879 if (obc%segnum_u(i,j) .ne. 0)
then
880 if (obc%segment(obc%segnum_u(i,j))%direction == obc_direction_e)
then
884 h1(:) = h_old(i+1,j,:)
885 h2(:) = h_new(i+1,j,:)
889 call remapping_core_h(cs_remapping, nz, h1, u(i,j,:), nz, h2, &
890 u_column, h_neglect, h_neglect_edge)
891 u(i,j,:) = u_column(:)
892 endif ;
enddo ;
enddo
895 if (show_call_tree)
call calltree_waypoint(
"u remapped (remap_all_state_vars)")
898 if (
present(v) )
then
900 do j = g%jscB,g%jecB ;
do i = g%isc,g%iec ;
if (g%mask2dCv(i,j)>0.)
then
902 h1(:) = 0.5 * ( h_old(i,j,:) + h_old(i,j+1,:) )
903 if (cs_ale%remap_uv_using_old_alg)
then
904 dx(:) = 0.5 * ( dxinterface(i,j,:) + dxinterface(i,j+1,:) )
906 h2(k) = max( 0., h1(k) + ( dx(k+1) - dx(k) ) )
909 h2(:) = 0.5 * ( h_new(i,j,:) + h_new(i,j+1,:) )
911 if (
associated(obc))
then
912 if (obc%segnum_v(i,j) .ne. 0)
then
913 if (obc%segment(obc%segnum_v(i,j))%direction == obc_direction_n)
then
917 h1(:) = h_old(i,j+1,:)
918 h2(:) = h_new(i,j+1,:)
922 call remapping_core_h(cs_remapping, nz, h1, v(i,j,:), nz, h2, &
923 u_column, h_neglect, h_neglect_edge)
924 v(i,j,:) = u_column(:)
925 endif ;
enddo ;
enddo
928 if (cs_ale%id_vert_remap_h > 0)
call post_data(cs_ale%id_vert_remap_h, h_old, cs_ale%diag)
929 if ((cs_ale%id_vert_remap_h_tendency > 0) .and.
present(dt))
then
930 do k = 1, nz ;
do j = g%jsc,g%jec ;
do i = g%isc,g%iec
931 work_cont(i,j,k) = (h_new(i,j,k) - h_old(i,j,k))*idt
932 enddo ;
enddo ;
enddo
933 call post_data(cs_ale%id_vert_remap_h_tendency, work_cont, cs_ale%diag)
935 if (show_call_tree)
call calltree_waypoint(
"v remapped (remap_all_state_vars)")
936 if (show_call_tree)
call calltree_leave(
"remap_all_state_vars()")
938 end subroutine remap_all_state_vars
944 subroutine ale_remap_scalar(CS, G, GV, nk_src, h_src, s_src, h_dst, s_dst, all_cells, old_remap, answers_2018 )
946 type(ocean_grid_type),
intent(in) :: g
948 integer,
intent(in) :: nk_src
949 real,
dimension(SZI_(G),SZJ_(G),nk_src),
intent(in) :: h_src
951 real,
dimension(SZI_(G),SZJ_(G),nk_src),
intent(in) :: s_src
952 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(in) :: h_dst
954 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(inout) :: s_dst
955 logical,
optional,
intent(in) :: all_cells
958 logical,
optional,
intent(in) :: old_remap
960 logical,
optional,
intent(in) :: answers_2018
965 integer :: i, j, k, n_points
967 real :: h_neglect, h_neglect_edge
968 logical :: ignore_vanished_layers, use_remapping_core_w, use_2018_remap
970 ignore_vanished_layers = .false.
971 if (
present(all_cells)) ignore_vanished_layers = .not. all_cells
972 use_remapping_core_w = .false.
973 if (
present(old_remap)) use_remapping_core_w = old_remap
975 use_2018_remap = .true. ;
if (
present(answers_2018)) use_2018_remap = answers_2018
977 if (.not.use_2018_remap)
then
978 h_neglect = gv%H_subroundoff ; h_neglect_edge = gv%H_subroundoff
979 elseif (gv%Boussinesq)
then
980 h_neglect = gv%m_to_H*1.0e-30 ; h_neglect_edge = gv%m_to_H*1.0e-10
982 h_neglect = gv%kg_m2_to_H*1.0e-30 ; h_neglect_edge = gv%kg_m2_to_H*1.0e-10
986 do j = g%jsc,g%jec ;
do i = g%isc,g%iec
987 if (g%mask2dT(i,j) > 0.)
then
988 if (ignore_vanished_layers)
then
991 if (h_src(i,j,k)>0.) n_points = n_points + 1
995 if (use_remapping_core_w)
then
996 call dzfromh1h2( n_points, h_src(i,j,1:n_points), gv%ke, h_dst(i,j,:), dx )
997 call remapping_core_w(cs, n_points, h_src(i,j,1:n_points), s_src(i,j,1:n_points), &
998 gv%ke, dx, s_dst(i,j,:), h_neglect, h_neglect_edge)
1000 call remapping_core_h(cs, n_points, h_src(i,j,1:n_points), s_src(i,j,1:n_points), &
1001 gv%ke, h_dst(i,j,:), s_dst(i,j,:), h_neglect, h_neglect_edge)
1008 end subroutine ale_remap_scalar
1013 subroutine ts_plm_edge_values( CS, S_t, S_b, T_t, T_b, G, GV, tv, h, bdry_extrap )
1014 type(ocean_grid_type),
intent(in) :: g
1016 type(
ale_cs),
intent(inout) :: cs
1017 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1018 intent(inout) :: s_t
1019 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1020 intent(inout) :: s_b
1021 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1022 intent(inout) :: t_t
1023 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1024 intent(inout) :: t_b
1026 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1028 logical,
intent(in) :: bdry_extrap
1031 call ale_plm_edge_values( cs, g, gv, h, tv%S, bdry_extrap, s_t, s_b )
1032 call ale_plm_edge_values( cs, g, gv, h, tv%T, bdry_extrap, t_t, t_b )
1034 end subroutine ts_plm_edge_values
1038 subroutine ale_plm_edge_values( CS, G, GV, h, Q, bdry_extrap, Q_t, Q_b )
1040 type(ocean_grid_type),
intent(in) :: g
1042 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1044 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1046 logical,
intent(in) :: bdry_extrap
1048 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1049 intent(inout) :: q_t
1050 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1051 intent(inout) :: q_b
1058 if (.not.cs%answers_2018)
then
1059 h_neglect = gv%H_subroundoff
1060 elseif (gv%Boussinesq)
then
1061 h_neglect = gv%m_to_H*1.0e-30
1063 h_neglect = gv%kg_m2_to_H*1.0e-30
1067 do j = g%jsc-1,g%jec+1 ;
do i = g%isc-1,g%iec+1
1070 slp(k) = plm_slope_wa(h(i,j,k-1), h(i,j,k), h(i,j,k+1), h_neglect, q(i,j,k-1), q(i,j,k), q(i,j,k+1))
1075 mslp = plm_monotonized_slope(q(i,j,k-1), q(i,j,k), q(i,j,k+1), slp(k-1), slp(k), slp(k+1))
1076 q_t(i,j,k) = q(i,j,k) - 0.5 * mslp
1077 q_b(i,j,k) = q(i,j,k) + 0.5 * mslp
1079 if (bdry_extrap)
then
1080 mslp = - plm_extrapolate_slope(h(i,j,2), h(i,j,1), h_neglect, q(i,j,2), q(i,j,1))
1081 q_t(i,j,1) = q(i,j,1) - 0.5 * mslp
1082 q_b(i,j,1) = q(i,j,1) + 0.5 * mslp
1083 mslp = plm_extrapolate_slope(h(i,j,gv%ke-1), h(i,j,gv%ke), h_neglect, q(i,j,gv%ke-1), q(i,j,gv%ke))
1084 q_t(i,j,gv%ke) = q(i,j,gv%ke) - 0.5 * mslp
1085 q_b(i,j,gv%ke) = q(i,j,gv%ke) + 0.5 * mslp
1087 q_t(i,j,1) = q(i,j,1)
1088 q_b(i,j,1) = q(i,j,1)
1089 q_t(i,j,gv%ke) = q(i,j,gv%ke)
1090 q_b(i,j,gv%ke) = q(i,j,gv%ke)
1095 end subroutine ale_plm_edge_values
1099 subroutine ts_ppm_edge_values( CS, S_t, S_b, T_t, T_b, G, GV, tv, h, bdry_extrap )
1100 type(ocean_grid_type),
intent(in) :: g
1102 type(
ale_cs),
intent(inout) :: cs
1103 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1104 intent(inout) :: s_t
1105 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1106 intent(inout) :: s_b
1107 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1108 intent(inout) :: t_t
1109 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1110 intent(inout) :: t_b
1112 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
1114 logical,
intent(in) :: bdry_extrap
1121 real,
dimension(CS%nk,2) :: &
1123 real,
dimension(CS%nk,3) :: &
1125 real :: h_neglect, h_neglect_edge
1127 if (.not.cs%answers_2018)
then
1128 h_neglect = gv%H_subroundoff ; h_neglect_edge = gv%H_subroundoff
1129 elseif (gv%Boussinesq)
then
1130 h_neglect = gv%m_to_H*1.0e-30 ; h_neglect_edge = gv%m_to_H*1.0e-10
1132 h_neglect = gv%kg_m2_to_H*1.0e-30 ; h_neglect_edge = gv%kg_m2_to_H*1.0e-10
1137 do j = g%jsc-1,g%jec+1 ;
do i = g%isc-1,g%iec+1
1141 tmp(:) = tv%S(i,j,:)
1145 ppol_coefs(:,:) = 0.0
1146 call edge_values_implicit_h4( gv%ke, htmp, tmp, ppol_e, h_neglect=h_neglect_edge, &
1147 answers_2018=cs%answers_2018 )
1148 call ppm_reconstruction( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect, &
1149 answers_2018=cs%answers_2018 )
1151 call ppm_boundary_extrapolation( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1154 s_t(i,j,k) = ppol_e(k,1)
1155 s_b(i,j,k) = ppol_e(k,2)
1160 ppol_coefs(:,:) = 0.0
1161 tmp(:) = tv%T(i,j,:)
1162 if (cs%answers_2018)
then
1163 call edge_values_implicit_h4( gv%ke, htmp, tmp, ppol_e, h_neglect=1.0e-10*gv%m_to_H, &
1164 answers_2018=cs%answers_2018 )
1166 call edge_values_implicit_h4( gv%ke, htmp, tmp, ppol_e, h_neglect=gv%H_subroundoff, &
1167 answers_2018=cs%answers_2018 )
1169 call ppm_reconstruction( gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect, &
1170 answers_2018=cs%answers_2018 )
1172 call ppm_boundary_extrapolation(gv%ke, htmp, tmp, ppol_e, ppol_coefs, h_neglect )
1175 t_t(i,j,k) = ppol_e(k,1)
1176 t_b(i,j,k) = ppol_e(k,2)
1181 end subroutine ts_ppm_edge_values
1185 subroutine ale_initregridding(GV, US, max_depth, param_file, mdl, regridCS)
1188 real,
intent(in) :: max_depth
1190 character(len=*),
intent(in) :: mdl
1193 character(len=30) :: coord_mode
1195 call get_param(param_file, mdl,
"REGRIDDING_COORDINATE_MODE", coord_mode, &
1196 "Coordinate mode for vertical regridding. "//&
1197 "Choose among the following possibilities: "//&
1198 trim(regriddingcoordinatemodedoc), &
1199 default=default_coordinate_mode, fail_if_missing=.true.)
1201 call initialize_regridding(regridcs, gv, us, max_depth, param_file, mdl, coord_mode,
'',
'')
1203 end subroutine ale_initregridding
1206 function ale_getcoordinate( CS )
1209 real,
dimension(CS%nk+1) :: ale_getcoordinate
1210 ale_getcoordinate(:) = getcoordinateinterfaces( cs%regridCS, undo_scaling=.true. )
1212 end function ale_getcoordinate
1216 function ale_getcoordinateunits( CS )
1219 character(len=20) :: ale_getcoordinateunits
1221 ale_getcoordinateunits = getcoordinateunits( cs%regridCS )
1223 end function ale_getcoordinateunits
1227 logical function ale_remap_init_conds( CS )
1230 ale_remap_init_conds = .false.
1231 if (
associated(cs)) ale_remap_init_conds = cs%remap_after_initialization
1232 end function ale_remap_init_conds
1235 subroutine ale_update_regrid_weights( dt, CS )
1236 real,
intent(in) :: dt
1237 type(
ale_cs),
pointer :: cs
1241 if (
associated(cs))
then
1243 if (cs%regrid_time_scale > 0.0)
then
1244 w = cs%regrid_time_scale / (cs%regrid_time_scale + dt)
1246 call set_regrid_params(cs%regridCS, old_grid_weight=w)
1249 end subroutine ale_update_regrid_weights
1254 subroutine ale_updateverticalgridtype(CS, GV)
1261 gv%sInterface(1:nk+1) = getcoordinateinterfaces( cs%regridCS, undo_scaling=.true. )
1262 gv%sLayer(1:nk) = 0.5*( gv%sInterface(1:nk) + gv%sInterface(2:nk+1) )
1263 gv%zAxisUnits = getcoordinateunits( cs%regridCS )
1264 gv%zAxisLongName = getcoordinateshortname( cs%regridCS )
1268 end subroutine ale_updateverticalgridtype
1274 subroutine ale_writecoordinatefile( CS, GV, directory )
1277 character(len=*),
intent(in) :: directory
1279 character(len=240) :: filepath
1281 type(fieldtype) :: fields(2)
1283 real :: ds(gv%ke), dsi(gv%ke+1)
1285 filepath = trim(directory) // trim(
"Vertical_coordinate")
1286 ds(:) = getcoordinateresolution( cs%regridCS, undo_scaling=.true. )
1288 dsi(2:gv%ke) = 0.5*( ds(1:gv%ke-1) + ds(2:gv%ke) )
1289 dsi(gv%ke+1) = 0.5*ds(gv%ke)
1291 vars(1) = var_desc(
'ds', getcoordinateunits( cs%regridCS ), &
1292 'Layer Coordinate Thickness',
'1',
'L',
'1')
1293 vars(2) = var_desc(
'ds_interface', getcoordinateunits( cs%regridCS ), &
1294 'Layer Center Coordinate Separation',
'1',
'i',
'1')
1296 call create_file(unit, trim(filepath), vars, 2, fields, single_file, gv=gv)
1297 call write_field(unit, fields(1), ds)
1298 call write_field(unit, fields(2), dsi)
1299 call close_file(unit)
1301 end subroutine ale_writecoordinatefile
1305 subroutine ale_initthicknesstocoord( CS, G, GV, h )
1307 type(ocean_grid_type),
intent(in) :: g
1309 real,
dimension(SZI_(G),SZJ_(G),SZK_(GV)),
intent(out) :: h
1314 do j = g%jsd,g%jed ;
do i = g%isd,g%ied
1315 h(i,j,:) = gv%Z_to_H * getstaticthickness( cs%regridCS, 0., g%bathyT(i,j) )
1318 end subroutine ale_initthicknesstocoord