MOM_boundary_update.F90

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Controls where open boundary conditions are applied
7
8use mom_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end, clock_routine
9use mom_diag_mediator, only : time_type
10use mom_error_handler, only : mom_mesg, mom_error, fatal, warning
11use mom_file_parser, only : get_param, log_version, param_file_type, log_param
12use mom_grid, only : ocean_grid_type
18use mom_tracer_registry, only : tracer_registry_type
30
31implicit none ; private
32
33#include <MOM_memory.h>
34
36public update_obc_data
37
38!> The control structure for the MOM_boundary_update module
39type, public :: update_obc_cs ; private
40 logical :: use_kelvin = .false. !< If true, use the Kelvin wave open boundary.
41 logical :: use_tidal_bay = .false. !< If true, use the tidal_bay open boundary.
42 logical :: use_shelfwave = .false. !< If true, use the shelfwave open boundary.
43 logical :: use_dyed_channel = .false. !< If true, use the dyed channel open boundary.
44 logical :: debug_obcs = .false. !< If true, write verbose OBC values for debugging purposes.
45 logical :: value_update_bug = .true. !< If true, recover a bug that OBC segment data does not
46 !! update if all segments use 'value' and none uses 'file'.
47 integer :: nk_obc_debug = 0 !< The number of layers of OBC segment data to write out
48 !! in full when DEBUG_OBCS is true.
49 !>@{ Pointers to the control structures for named OBC specifications
50 type(kelvin_obc_cs), pointer :: kelvin_obc_csp => null()
51 type(tidal_bay_obc_cs) :: tidal_bay_obc
52 type(shelfwave_obc_cs), pointer :: shelfwave_obc_csp => null()
53 type(dyed_channel_obc_cs), pointer :: dyed_channel_obc_csp => null()
54 !>@}
55end type update_obc_cs
56
57integer :: id_clock_pass !< A CPU time clock ID
58
59! character(len=40) :: mdl = "MOM_boundary_update" ! This module's name.
60
61contains
62
63!> The following subroutines and associated definitions provide the
64!! machinery to register and call the subroutines that initialize
65!! open boundary conditions.
66subroutine call_obc_register(G, GV, US, param_file, CS, OBC, tr_Reg)
67 type(ocean_grid_type), intent(in) :: g !< Ocean grid structure
68 type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
69 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
70 type(param_file_type), intent(in) :: param_file !< Parameter file to parse
71 type(update_obc_cs), pointer :: cs !< Control structure for OBCs
72 type(ocean_obc_type), pointer :: obc !< Open boundary structure
73 type(tracer_registry_type), pointer :: tr_reg !< Tracer registry.
74
75 ! Local variables
76 logical :: debug
77 logical :: enable_bugs ! If true, the defaults for recently added bug-fix flags are set to
78 ! recreate the bugs, or if false bugs are only used if actively selected.
79 character(len=200) :: config
80 character(len=40) :: mdl = "MOM_boundary_update" ! This module's name.
81 ! This include declares and sets the variable "version".
82# include "version_variable.h"
83 if (associated(cs)) then
84 call mom_error(warning, "call_OBC_register called with an associated "// &
85 "control structure.")
86 return
87 else ; allocate(cs) ; endif
88
89 call log_version(param_file, mdl, version, "")
90
91 call get_param(param_file, mdl, "ENABLE_BUGS_BY_DEFAULT", enable_bugs, &
92 default=.true., do_not_log=.true.) ! This is logged from MOM.F90.
93 call get_param(param_file, mdl, "OBC_VALUE_UPDATE_BUG", cs%value_update_bug, &
94 "If true, recover a bug that OBC segment data does not update if all segments "//&
95 "use 'value' and none uses 'file'.", default=enable_bugs)
96 call get_param(param_file, mdl, "USE_TIDAL_BAY_OBC", cs%use_tidal_bay, &
97 "If true, use the tidal_bay open boundary.", &
98 default=.false.)
99 call get_param(param_file, mdl, "USE_KELVIN_WAVE_OBC", cs%use_Kelvin, &
100 "If true, use the Kelvin wave open boundary.", &
101 default=.false.)
102 call get_param(param_file, mdl, "USE_SHELFWAVE_OBC", cs%use_shelfwave, &
103 "If true, use the shelfwave open boundary.", &
104 default=.false.)
105 call get_param(param_file, mdl, "USE_DYED_CHANNEL_OBC", cs%use_dyed_channel, &
106 "If true, use the dyed channel open boundary.", &
107 default=.false.)
108 call get_param(param_file, mdl, "OBC_USER_CONFIG", config, &
109 "A string that sets how the user code is invoked to set open boundary data: \n"//&
110 " DOME - specified inflow on northern boundary\n"//&
111 " dyed_channel - supercritical with dye on the inflow boundary\n"//&
112 " dyed_obcs - circle_obcs with dyes on the open boundaries\n"//&
113 " Kelvin - barotropic Kelvin wave forcing on the western boundary\n"//&
114 " shelfwave - Flather with shelf wave forcing on western boundary\n"//&
115 " supercritical - now only needed here for the allocations\n"//&
116 " tidal_bay - Flather with tidal forcing on eastern boundary\n"//&
117 " USER - user specified", default="none", do_not_log=.true.)
118 call get_param(param_file, mdl, "DEBUG", debug, &
119 "If true, write out verbose debugging data.", &
120 default=.false., debuggingparam=.true.)
121 call get_param(param_file, mdl, "DEBUG_OBCS", cs%debug_OBCs, &
122 "If true, write out verbose debugging data about OBCs.", &
123 default=.false., debuggingparam=.true.)
124 call get_param(param_file, mdl, "NK_OBC_DEBUG", cs%nk_OBC_debug, &
125 "The number of layers of OBC segment data to write out in full "//&
126 "when DEBUG_OBCS is true.", &
127 default=0, debuggingparam=.true., do_not_log=.not.cs%debug_OBCs)
128
129 if (trim(config) == "DOME") then
130 call register_dome_obc(param_file, us, obc, tr_reg)
131! elseif (trim(config) == "tidal_bay") then
132! elseif (trim(config) == "Kelvin") then
133! elseif (trim(config) == "shelfwave") then
134! elseif (trim(config) == "dyed_channel") then
135 endif
136
137 if (cs%use_tidal_bay) cs%use_tidal_bay = &
138 register_tidal_bay_obc(param_file, cs%tidal_bay_OBC, us)
139 if (cs%use_Kelvin) cs%use_Kelvin = &
140 register_kelvin_obc(param_file, cs%Kelvin_OBC_CSp, us)
141 if (cs%use_shelfwave) cs%use_shelfwave = &
142 register_shelfwave_obc(param_file, cs%shelfwave_OBC_CSp, g, us)
143 if (cs%use_dyed_channel) cs%use_dyed_channel = &
144 register_dyed_channel_obc(param_file, cs%dyed_channel_OBC_CSp, us)
145
146end subroutine call_obc_register
147
148!> Calls appropriate routine to update the open boundary conditions.
149subroutine update_obc_data(OBC, G, GV, US, tv, h, CS, Time)
150 type(ocean_grid_type), intent(in) :: g !< Ocean grid structure
151 type(verticalgrid_type), intent(in) :: gv !< Ocean vertical grid structure
152 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
153 type(thermo_var_ptrs), intent(in) :: tv !< Thermodynamics structure
154 real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(inout) :: h !< layer thicknesses [H ~> m or kg m-2]
155 type(ocean_obc_type), pointer :: obc !< Open boundary structure
156 type(update_obc_cs), pointer :: cs !< Control structure for OBCs
157 type(time_type), intent(in) :: time !< Model time
158
159 if (cs%use_tidal_bay) &
160 call tidal_bay_set_obc_data(obc, cs%tidal_bay_OBC, g, gv, us, h, time)
161 if (cs%use_Kelvin) &
162 call kelvin_set_obc_data(obc, cs%Kelvin_OBC_CSp, g, gv, us, h, time)
163 if (cs%use_shelfwave) &
164 call shelfwave_set_obc_data(obc, cs%shelfwave_OBC_CSp, g, gv, us, h, time)
165 if (cs%use_dyed_channel) &
166 call dyed_channel_update_flow(obc, cs%dyed_channel_OBC_CSp, g, gv, us, h, time)
167
168 if (.not. obc%user_BCs_set_globally) then
169 ! Update dynamics
170 if (obc%any_needs_IO_for_data) &
171 call read_obc_dynamics_data(g, gv, us, obc, tv, h, time)
172 if ((.not. cs%value_update_bug) .or. &
173 (obc%any_needs_IO_for_data .or. obc%add_tide_constituents)) &
174 call update_obc_dynamics_data(g, gv, us, obc, h, time)
175 ! Update tracers: this is the old incorrect path. See step_MOM_tracer_dyn for the locked path.
176 ! If DT_OBC_SEG_UPDATE_OBGC is used (not recommended), BGC has its own update schedule, which
177 ! may happen in between tracer steps.
178 if ((.not. obc%ignore_dt_obc_bgc) .and. obc%any_needs_IO_for_data .and. obc%tracer_dz_bug) then
179 call read_obc_tracer_data(g, gv, us, obc, time, include_bgc=obc%update_OBC_seg_data)
180 call update_obc_tracer_data(obc, include_bgc=obc%update_OBC_seg_data)
181 endif
182 endif
183
184 if (cs%debug_OBCs) call chksum_obc_segments(obc, g, gv, us, cs%nk_OBC_debug)
185
186end subroutine update_obc_data
187
188!> Clean up the OBC registry.
189subroutine obc_register_end(CS)
190 type(update_obc_cs), pointer :: cs !< Control structure for OBCs
191
192 if (cs%use_Kelvin) call kelvin_obc_end(cs%Kelvin_OBC_CSp)
193
194 if (associated(cs)) deallocate(cs)
195end subroutine obc_register_end
196
197!> \namespace mom_boundary_update
198!! This module updates the open boundary arrays when time-varying.
199!! It caused a circular dependency with the tidal_bay and other setups when in
200!! MOM_open_boundary.
201!!
202!! A small fragment of the grid is shown below:
203!!
204!! j+1 x ^ x ^ x At x: q, CoriolisBu
205!! j+1 > o > o > At ^: v, tauy
206!! j x ^ x ^ x At >: u, taux
207!! j > o > o > At o: h, bathyT, buoy, tr, T, S, Rml, ustar
208!! j-1 x ^ x ^ x
209!! i-1 i i+1 At x & ^:
210!! i i+1 At > & o:
211!!
212!! The boundaries always run through q grid points (x).
213
214end module mom_boundary_update