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