@@ -24,7 +24,7 @@ module MOM_internal_tides
24
24
use MOM_restart, only : register_restart_field, MOM_restart_CS, restart_init, save_restart
25
25
use MOM_restart, only : lock_check, restart_registry_lock
26
26
use MOM_spatial_means, only : global_area_integral
27
- use MOM_string_functions, only: extract_real
27
+ use MOM_string_functions, only: extract_real, uppercase
28
28
use MOM_time_manager, only : time_type, time_type_to_real, operator (+ ), operator (/ ), operator (- )
29
29
use MOM_unit_scaling, only : unit_scale_type
30
30
use MOM_variables, only : surface, thermo_var_ptrs, vertvisc_type
@@ -154,6 +154,7 @@ module MOM_internal_tides
154
154
type (time_type), pointer :: Time = > NULL () ! < A pointer to the model's clock.
155
155
type (group_pass_type) :: pass_En ! < Pass 5d array Energy as a group of 3d arrays
156
156
character (len= 200 ) :: inputdir ! < directory to look for coastline angle file
157
+ integer :: itides_adv_limiter ! < The type of limiter to use for the energy advection scheme
157
158
real , allocatable , dimension (:,:,:,:) :: decay_rate_2d ! < rate at which internal tide energy is
158
159
! ! lost to the interior ocean internal wave field
159
160
! ! as a function of longitude, latitude, frequency
@@ -260,6 +261,13 @@ module MOM_internal_tides
260
261
! >@}
261
262
end type loop_bounds_type
262
263
264
+ ! >@{ Enumeration values for numerical schemes
265
+ integer , parameter :: LIMITER_ADV_MINMOD = 1
266
+ integer , parameter :: LIMITER_ADV_POSITIVE = 2
267
+ character * (20 ), parameter :: LIMITER_ADV_MINMOD_STRING = " MINMOD"
268
+ character * (20 ), parameter :: LIMITER_ADV_POSITIVE_STRING = " POSITIVE"
269
+ ! >@}
270
+
263
271
contains
264
272
265
273
! > Calls subroutines in this file that are needed to refract, propagate,
@@ -2267,7 +2275,8 @@ subroutine propagate_x(En, speed_x, Cgx_av, dCgx, dt, G, US, Nangle, CS, LB, res
2267
2275
EnL(i,j) = En(i,j,a) ; EnR(i,j) = En(i,j,a)
2268
2276
enddo ; enddo
2269
2277
else
2270
- call PPM_reconstruction_x(En(:,:,a), EnL, EnR, G, LB, simple_2nd= CS% simple_2nd)
2278
+ call PPM_reconstruction_x(En(:,:,a), EnL, EnR, G, LB, &
2279
+ simple_2nd= CS% simple_2nd, adv_limiter= CS% itides_adv_limiter)
2271
2280
endif
2272
2281
2273
2282
do j= jsh,jeh
@@ -2349,7 +2358,8 @@ subroutine propagate_y(En, speed_y, Cgy_av, dCgy, dt, G, US, Nangle, CS, LB, res
2349
2358
EnL(i,j) = En(i,j,a) ; EnR(i,j) = En(i,j,a)
2350
2359
enddo ; enddo
2351
2360
else
2352
- call PPM_reconstruction_y(En(:,:,a), EnL, EnR, G, LB, simple_2nd= CS% simple_2nd)
2361
+ call PPM_reconstruction_y(En(:,:,a), EnL, EnR, G, LB, &
2362
+ simple_2nd= CS% simple_2nd, adv_limiter= CS% itides_adv_limiter)
2353
2363
endif
2354
2364
2355
2365
do J= jsh-1 ,jeh
@@ -2740,7 +2750,7 @@ subroutine correct_halo_rotation(En, test, G, NAngle, halo)
2740
2750
end subroutine correct_halo_rotation
2741
2751
2742
2752
! > Calculates left/right edge values for PPM reconstruction in x-direction.
2743
- subroutine PPM_reconstruction_x (h_in , h_l , h_r , G , LB , simple_2nd )
2753
+ subroutine PPM_reconstruction_x (h_in , h_l , h_r , G , LB , simple_2nd , adv_limiter )
2744
2754
type (ocean_grid_type), intent (in ) :: G ! < The ocean's grid structure.
2745
2755
real , dimension (SZI_(G),SZJ_(G)), intent (in ) :: h_in ! < Energy density in a sector (2D)
2746
2756
! ! [H Z2 T-2 ~> m3 s-2 or J m-2]
@@ -2752,6 +2762,8 @@ subroutine PPM_reconstruction_x(h_in, h_l, h_r, G, LB, simple_2nd)
2752
2762
logical , intent (in ) :: simple_2nd ! < If true, use the arithmetic mean
2753
2763
! ! energy densities as default edge values
2754
2764
! ! for a simple 2nd order scheme.
2765
+ integer , intent (in ) :: adv_limiter ! < The type of limiter used
2766
+
2755
2767
! Local variables
2756
2768
real , dimension (SZI_(G),SZJ_(G)) :: slp ! The slope in energy density times the cell width
2757
2769
! [H Z2 T-2 ~> m3 s-2 or J m-2]
@@ -2815,11 +2827,17 @@ subroutine PPM_reconstruction_x(h_in, h_l, h_r, G, LB, simple_2nd)
2815
2827
enddo ; enddo
2816
2828
endif
2817
2829
2818
- call PPM_limit_pos(h_in, h_l, h_r, 0.0 , G, isl, iel, jsl, jel)
2830
+ select case (adv_limiter)
2831
+ case (LIMITER_ADV_POSITIVE)
2832
+ call PPM_limit_pos(h_in, h_l, h_r, 0.0 , G, isl, iel, jsl, jel)
2833
+ case (LIMITER_ADV_MINMOD)
2834
+ call minmod_limiter(h_in, h_l, h_r, G, isl, iel, jsl, jel)
2835
+ end select
2836
+
2819
2837
end subroutine PPM_reconstruction_x
2820
2838
2821
2839
! > Calculates left/right edge valus for PPM reconstruction in y-direction.
2822
- subroutine PPM_reconstruction_y (h_in , h_l , h_r , G , LB , simple_2nd )
2840
+ subroutine PPM_reconstruction_y (h_in , h_l , h_r , G , LB , simple_2nd , adv_limiter )
2823
2841
type (ocean_grid_type), intent (in ) :: G ! < The ocean's grid structure.
2824
2842
real , dimension (SZI_(G),SZJ_(G)), intent (in ) :: h_in ! < Energy density in a sector (2D)
2825
2843
! ! [H Z2 T-2 ~> m3 s-2 or J m-2]
@@ -2831,6 +2849,8 @@ subroutine PPM_reconstruction_y(h_in, h_l, h_r, G, LB, simple_2nd)
2831
2849
logical , intent (in ) :: simple_2nd ! < If true, use the arithmetic mean
2832
2850
! ! energy densities as default edge values
2833
2851
! ! for a simple 2nd order scheme.
2852
+ integer , intent (in ) :: adv_limiter ! < The type of limiter used
2853
+
2834
2854
! Local variables
2835
2855
real , dimension (SZI_(G),SZJ_(G)) :: slp ! The slope in energy density times the cell width
2836
2856
! [H Z2 T-2 ~> m3 s-2 or J m-2]
@@ -2892,7 +2912,13 @@ subroutine PPM_reconstruction_y(h_in, h_l, h_r, G, LB, simple_2nd)
2892
2912
enddo ; enddo
2893
2913
endif
2894
2914
2895
- call PPM_limit_pos(h_in, h_l, h_r, 0.0 , G, isl, iel, jsl, jel)
2915
+ select case (adv_limiter)
2916
+ case (LIMITER_ADV_POSITIVE)
2917
+ call PPM_limit_pos(h_in, h_l, h_r, 0.0 , G, isl, iel, jsl, jel)
2918
+ case (LIMITER_ADV_MINMOD)
2919
+ call minmod_limiter(h_in, h_l, h_r, G, isl, iel, jsl, jel)
2920
+ end select
2921
+
2896
2922
end subroutine PPM_reconstruction_y
2897
2923
2898
2924
! > Limits the left/right edge values of the PPM reconstruction
@@ -2941,6 +2967,42 @@ subroutine PPM_limit_pos(h_in, h_L, h_R, h_min, G, iis, iie, jis, jie)
2941
2967
enddo ; enddo
2942
2968
end subroutine PPM_limit_pos
2943
2969
2970
+ ! > Limits the left/right edge values using the simple minmod limiter
2971
+ ! ! written in a way that avoids branching in favor of intrinsics
2972
+ subroutine minmod_limiter (h_in , h_L , h_R , G , iis , iie , jis , jie )
2973
+ type (ocean_grid_type), intent (in ) :: G ! < The ocean's grid structure.
2974
+ real , dimension (SZI_(G),SZJ_(G)), intent (in ) :: h_in ! < Energy density in each sector (2D)
2975
+ ! ! [H Z2 T-2 ~> m3 s-2 or J m-2]
2976
+ real , dimension (SZI_(G),SZJ_(G)), intent (inout ) :: h_L ! < Left edge value of reconstruction
2977
+ ! ! [H Z2 T-2 ~> m3 s-2 or J m-2]
2978
+ real , dimension (SZI_(G),SZJ_(G)), intent (inout ) :: h_R ! < Right edge value of reconstruction
2979
+ ! ! [H Z2 T-2 ~> m3 s-2 or J m-2]
2980
+ integer , intent (in ) :: iis ! < Start i-index for computations
2981
+ integer , intent (in ) :: iie ! < End i-index for computations
2982
+ integer , intent (in ) :: jis ! < Start j-index for computations
2983
+ integer , intent (in ) :: jie ! < End j-index for computations
2984
+ ! Local variables
2985
+ real :: sign_h_L, sign_h_R, sign_h_in ! the signs of the edge and center values
2986
+ real :: sign_h_L_in, sign_h_R_in ! products of signs, detect crossing the zero line
2987
+ integer :: i, j
2988
+
2989
+ do j= jis,jie ; do i= iis,iie
2990
+
2991
+ sign_h_L = sign (1.0d0 , h_L(i,j))
2992
+ sign_h_R = sign (1.0d0 , h_R(i,j))
2993
+ sign_h_in = sign (1.0d0 , h_in(i,j))
2994
+
2995
+ sign_h_L_in = sign_h_L * sign_h_in
2996
+ sign_h_R_in = sign_h_R * sign_h_in
2997
+
2998
+ ! if opposite signs, goes to zero else take the min of edge and centers values
2999
+ h_L(i,j) = (0.5 * (sign_h_L_in + 1.0 )) * (sign_h_L * min (abs (h_L(i,j)), abs (h_in(i,j))))
3000
+ h_R(i,j) = (0.5 * (sign_h_R_in + 1.0 )) * (sign_h_R * min (abs (h_R(i,j)), abs (h_in(i,j))))
3001
+
3002
+ enddo ; enddo
3003
+
3004
+ end subroutine minmod_limiter
3005
+
2944
3006
subroutine register_int_tide_restarts (G , GV , US , param_file , CS , restart_CS )
2945
3007
type (ocean_grid_type), intent (in ) :: G ! < The ocean's grid structure
2946
3008
type (verticalGrid_type),intent (in ):: GV ! < The ocean's vertical grid structure.
@@ -3131,6 +3193,7 @@ subroutine internal_tides_init(Time, G, GV, US, param_file, diag, CS)
3131
3193
character (len= 200 ) :: refl_pref_file, refl_dbl_file, trans_file
3132
3194
character (len= 200 ) :: h2_file, decay_file
3133
3195
character (len= 80 ) :: rough_var ! Input file variable names
3196
+ character (len= 80 ) :: tmpstr
3134
3197
3135
3198
character (len= 240 ), dimension (:), allocatable :: energy_fractions
3136
3199
character (len= 240 ) :: periods
@@ -3291,6 +3354,24 @@ subroutine internal_tides_init(Time, G, GV, US, param_file, diag, CS)
3291
3354
" 1st-order upwind advection. This scheme is highly " // &
3292
3355
" continuity solver. This scheme is highly " // &
3293
3356
" diffusive but may be useful for debugging." , default= .false. )
3357
+ call get_param(param_file, mdl, " INTERNAL_TIDE_ADV_LIMITER" , tmpstr, &
3358
+ " Choose the limiter scheme used for the internal tide advection scheme, " // &
3359
+ " available schemes are: \n" // &
3360
+ " \t POSITIVE - a positive definite scheme similar to the continuity solver. \n" // &
3361
+ " \t MINMOD - the simplest limiter." , default= LIMITER_ADV_MINMOD_STRING)
3362
+
3363
+ tmpstr = uppercase(tmpstr)
3364
+ select case (tmpstr)
3365
+ case (LIMITER_ADV_POSITIVE_STRING)
3366
+ CS% itides_adv_limiter = LIMITER_ADV_POSITIVE
3367
+ case (LIMITER_ADV_MINMOD_STRING)
3368
+ CS% itides_adv_limiter = LIMITER_ADV_MINMOD
3369
+ case default
3370
+ call MOM_mesg(' internal_tide_init: Advection limiter ="' // trim (tmpstr)// ' "' , 0 )
3371
+ call MOM_error(FATAL, " internal_tide_init: Unrecognized setting " // &
3372
+ " #define INTERNAL_TIDE_ADV_LIMITER " // trim (tmpstr)// " found in input file." )
3373
+ end select
3374
+
3294
3375
call get_param(param_file, mdl, " INTERNAL_TIDE_BACKGROUND_DRAG" , CS% apply_background_drag, &
3295
3376
" If true, the internal tide ray-tracing advection uses a background drag " // &
3296
3377
" term as a sink." , default= .false. )
0 commit comments