user_surface_forcing.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!> Template for user to code up surface forcing.
7
9use mom_diag_mediator, only : register_diag_field, diag_ctrl, safe_alloc_ptr
10use mom_domains, only : pass_var, pass_vector, agrid
11use mom_error_handler, only : mom_error, fatal, warning, is_root_pe
12use mom_file_parser, only : get_param, param_file_type, log_version
14use mom_forcing_type, only : allocate_forcing_type, allocate_mech_forcing
15use mom_grid, only : ocean_grid_type
16use mom_time_manager, only : time_type, operator(+), operator(/)
20use mom_variables, only : surface
21
22implicit none ; private
23
25
26!> This control structure should be used to store any run-time variables
27!! associated with the user-specified forcing.
28!!
29!! It can be readily modified for a specific case, and because it is private there
30!! will be no changes needed in other code (although they will have to be recompiled).
31type, public :: user_surface_forcing_cs ; private
32 ! The variables in the canonical example are used for some common
33 ! cases, but do not need to be used.
34
35 logical :: use_temperature !< If true, temperature and salinity are used as state variables.
36 logical :: restorebuoy !< If true, use restoring surface buoyancy forcing.
37 real :: rho0 !< The density used in the Boussinesq approximation [R ~> kg m-3].
38 real :: g_earth !< The gravitational acceleration [L2 Z-1 T-2 ~> m s-2].
39 real :: flux_const !< The restoring rate at the surface [Z T-1 ~> m s-1].
40 real :: rho_restore !< The density that is used to convert piston velocities into salt
41 !! or heat fluxes with salinity or temperature restoring [R ~> kg m-3]
42 real :: gust_const !< A constant unresolved background gustiness
43 !! that contributes to ustar [R Z2 T-2 ~> Pa].
44
45 type(diag_ctrl), pointer :: diag !< A structure that is used to regulate the
46 !! timing of diagnostic output.
48
49contains
50
51!> This subroutine sets the surface wind stresses, forces%taux and forces%tauy, in [R Z L T-2 ~> Pa].
52!! These are the stresses in the direction of the model grid (i.e. the same
53!! direction as the u- and v- velocities).
54subroutine user_wind_forcing(sfc_state, forces, day, G, US, CS)
55 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
56 !! describe the surface state of the ocean.
57 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
58 type(time_type), intent(in) :: day !< The time of the fluxes
59 type(ocean_grid_type), intent(inout) :: g !< The ocean's grid structure
60 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
61 type(user_surface_forcing_cs), pointer :: cs !< A pointer to the control structure returned
62 !! by a previous call to user_surface_forcing_init
63
64 ! Local variables
65 integer :: i, j, is, ie, js, je, isq, ieq, jsq, jeq
66
67 ! When modifying the code, comment out this error message. It is here
68 ! so that the original (unmodified) version is not accidentally used.
69 call mom_error(fatal, "User_wind_surface_forcing: " // &
70 "User forcing routine called without modification." )
71
72 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
73 isq = g%IscB ; ieq = g%IecB ; jsq = g%JscB ; jeq = g%JecB
74
75 ! Allocate the forcing arrays, if necessary.
76 call allocate_mech_forcing(g, forces, stress=.true., ustar=.true., tau_mag=.true.)
77
78 ! Set the surface wind stresses, in units of [R L Z T-2 ~> Pa]. A positive taux
79 ! accelerates the ocean to the (pseudo-)east.
80
81 ! The i-loop extends to is-1 so that taux can be used later in the
82 ! calculation of ustar - otherwise the lower bound would be Isq.
83 do j=js,je ; do i=is-1,ieq
84 ! Change this to the desired expression.
85 forces%taux(i,j) = g%mask2dCu(i,j) * 0.0*us%Pa_to_RLZ_T2
86 enddo ; enddo
87 do j=js-1,jeq ; do i=is,ie
88 forces%tauy(i,j) = g%mask2dCv(i,j) * 0.0 ! Change this to the desired expression.
89 enddo ; enddo
90
91 ! Set the surface friction velocity, in units of [Z T-1 ~> m s-1]. ustar
92 ! is always positive.
93 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
94 ! This expression can be changed if desired, but need not be.
95 forces%tau_mag(i,j) = g%mask2dT(i,j) * (cs%gust_const + &
96 us%L_to_Z*sqrt(0.5*((forces%taux(i-1,j)**2) + (forces%taux(i,j)**2)) + &
97 0.5*((forces%tauy(i,j-1)**2) + (forces%tauy(i,j)**2))))
98 if (associated(forces%ustar)) &
99 forces%ustar(i,j) = g%mask2dT(i,j) * sqrt(forces%tau_mag(i,j) * (1.0/cs%Rho0))
100 enddo ; enddo ; endif
101
102end subroutine user_wind_forcing
103
104!> This subroutine specifies the current surface fluxes of buoyancy or
105!! temperature and fresh water. It may also be modified to add
106!! surface fluxes of user provided tracers.
107subroutine user_buoyancy_forcing(sfc_state, fluxes, day, dt, G, US, CS)
108 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
109 !! describe the surface state of the ocean.
110 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
111 type(time_type), intent(in) :: day !< The time of the fluxes
112 real, intent(in) :: dt !< The amount of time over which
113 !! the fluxes apply [T ~> s]
114 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
115 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
116 type(user_surface_forcing_cs), pointer :: cs !< A pointer to the control structure returned
117 !! by a previous call to user_surface_forcing_init
118
119! This subroutine specifies the current surface fluxes of buoyancy or
120! temperature and fresh water. It may also be modified to add
121! surface fluxes of user provided tracers.
122
123! When temperature is used, there are long list of fluxes that need to be
124! set - essentially the same as for a full coupled model, but most of these
125! can be simply set to zero. The net fresh water flux should probably be
126! set in fluxes%evap and fluxes%lprec, with any salinity restoring
127! appearing in fluxes%vprec, and the other water flux components
128! (fprec, lrunoff and frunoff) left as arrays full of zeros.
129! Evap is usually negative and precip is usually positive. All heat fluxes
130! are in W m-2 and positive for heat going into the ocean. All fresh water
131! fluxes are in [R Z T-1 ~> kg m-2 s-1] and positive for water moving into the ocean.
132
133 ! Local variables
134 real :: temp_restore ! The temperature that is being restored toward [C ~> degC].
135 real :: salin_restore ! The salinity that is being restored toward [S ~> ppt]
136 real :: density_restore ! The potential density that is being restored
137 ! toward [R ~> kg m-3].
138 real :: rhoxcp ! The mean density times the heat capacity [Q R C-1 ~> J m-3 degC-1].
139 real :: buoy_rest_const ! A constant relating density anomalies to the
140 ! restoring buoyancy flux [L2 T-3 R-1 ~> m5 s-3 kg-1].
141
142 integer :: i, j, is, ie, js, je
143 integer :: isd, ied, jsd, jed
144
145 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
146 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
147
148 ! When modifying the code, comment out this error message. It is here
149 ! so that the original (unmodified) version is not accidentally used.
150 call mom_error(fatal, "User_buoyancy_surface_forcing: " // &
151 "User forcing routine called without modification." )
152
153 ! Allocate and zero out the forcing arrays, as necessary. This portion is
154 ! usually not changed.
155 if (cs%use_temperature) then
156 call safe_alloc_ptr(fluxes%evap, isd, ied, jsd, jed)
157 call safe_alloc_ptr(fluxes%lprec, isd, ied, jsd, jed)
158 call safe_alloc_ptr(fluxes%fprec, isd, ied, jsd, jed)
159 call safe_alloc_ptr(fluxes%lrunoff, isd, ied, jsd, jed)
160 call safe_alloc_ptr(fluxes%frunoff, isd, ied, jsd, jed)
161 call safe_alloc_ptr(fluxes%vprec, isd, ied, jsd, jed)
162
163 call safe_alloc_ptr(fluxes%sw, isd, ied, jsd, jed)
164 call safe_alloc_ptr(fluxes%lw, isd, ied, jsd, jed)
165 call safe_alloc_ptr(fluxes%latent, isd, ied, jsd, jed)
166 call safe_alloc_ptr(fluxes%sens, isd, ied, jsd, jed)
167 else ! This is the buoyancy only mode.
168 call safe_alloc_ptr(fluxes%buoy, isd, ied, jsd, jed)
169 endif
170
171
172 ! MODIFY THE CODE IN THE FOLLOWING LOOPS TO SET THE BUOYANCY FORCING TERMS.
173
174 if ( cs%use_temperature ) then
175 ! Set whichever fluxes are to be used here. Any fluxes that
176 ! are always zero do not need to be changed here.
177 do j=js,je ; do i=is,ie
178 ! Fluxes of fresh water through the surface are in units of [R Z T-1 ~> kg m-2 s-1]
179 ! and are positive downward - i.e. evaporation should be negative.
180 fluxes%evap(i,j) = -0.0 * g%mask2dT(i,j)
181 fluxes%lprec(i,j) = 0.0 * g%mask2dT(i,j)
182
183 ! vprec will be set later, if it is needed for salinity restoring.
184 fluxes%vprec(i,j) = 0.0
185
186 ! Heat fluxes are in units of [Q R Z T-1 ~> W m-2] and are positive into the ocean.
187 fluxes%lw(i,j) = 0.0 * g%mask2dT(i,j)
188 fluxes%latent(i,j) = 0.0 * g%mask2dT(i,j)
189 fluxes%sens(i,j) = 0.0 * g%mask2dT(i,j)
190 fluxes%sw(i,j) = 0.0 * g%mask2dT(i,j)
191 enddo ; enddo
192 else ! This is the buoyancy only mode.
193 do j=js,je ; do i=is,ie
194 ! fluxes%buoy is the buoyancy flux into the ocean [L2 T-3 ~> m2 s-3]. A positive
195 ! buoyancy flux is of the same sign as heating the ocean.
196 fluxes%buoy(i,j) = 0.0 * g%mask2dT(i,j)
197 enddo ; enddo
198 endif
199
200 if (cs%restorebuoy) then
201 if (cs%use_temperature) then
202 call safe_alloc_ptr(fluxes%heat_added, isd, ied, jsd, jed)
203 ! When modifying the code, comment out this error message. It is here
204 ! so that the original (unmodified) version is not accidentally used.
205 call mom_error(fatal, "User_buoyancy_surface_forcing: " // &
206 "Temperature and salinity restoring used without modification." )
207
208 rhoxcp = cs%rho_restore * fluxes%C_p
209 do j=js,je ; do i=is,ie
210 ! Set Temp_restore and Salin_restore to the temperature (in [C ~> degC]) and
211 ! salinity (in [S ~> ppt]) that are being restored toward.
212 temp_restore = 0.0
213 salin_restore = 0.0
214
215 fluxes%heat_added(i,j) = (g%mask2dT(i,j) * (rhoxcp * cs%Flux_const)) * &
216 (temp_restore - sfc_state%SST(i,j))
217 fluxes%vprec(i,j) = - (g%mask2dT(i,j) * (cs%rho_restore*cs%Flux_const)) * &
218 ((salin_restore - sfc_state%SSS(i,j)) / (0.5 * (salin_restore + sfc_state%SSS(i,j))))
219 enddo ; enddo
220 else
221 ! When modifying the code, comment out this error message. It is here
222 ! so that the original (unmodified) version is not accidentally used.
223 call mom_error(fatal, "User_buoyancy_surface_forcing: " // &
224 "Buoyancy restoring used without modification." )
225
226 ! The -1 is because density has the opposite sign to buoyancy.
227 buoy_rest_const = -1.0 * (cs%G_Earth * cs%Flux_const) / cs%rho_restore
228 do j=js,je ; do i=is,ie
229 ! Set density_restore to an expression for the surface potential
230 ! density [R ~> kg m-3] that is being restored toward.
231 density_restore = 1030.0*us%kg_m3_to_R
232
233 fluxes%buoy(i,j) = g%mask2dT(i,j) * buoy_rest_const * &
234 (density_restore - sfc_state%sfc_density(i,j))
235 enddo ; enddo
236 endif
237 endif ! end RESTOREBUOY
238
239end subroutine user_buoyancy_forcing
240
241!> This subroutine initializes the USER_surface_forcing module
242subroutine user_surface_forcing_init(Time, G, US, param_file, diag, CS)
243 type(time_type), intent(in) :: time !< The current model time
244 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
245 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
246 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
247 type(diag_ctrl), target, intent(in) :: diag !< A structure that is used to regulate diagnostic output.
248 type(user_surface_forcing_cs), pointer :: cs !< A pointer that is set to point to
249 !! the control structure for this module
250
251 ! This include declares and sets the variable "version".
252# include "version_variable.h"
253 character(len=40) :: mdl = "user_surface_forcing" ! This module's name.
254
255 if (associated(cs)) then
256 call mom_error(warning, "USER_surface_forcing_init called with an associated "// &
257 "control structure.")
258 return
259 endif
260 allocate(cs)
261 cs%diag => diag
262
263 ! Read all relevant parameters and write them to the model log.
264 call log_version(param_file, mdl, version, "")
265 call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", cs%use_temperature, &
266 "If true, Temperature and salinity are used as state "//&
267 "variables.", default=.true.)
268
269 call get_param(param_file, mdl, "G_EARTH", cs%G_Earth, &
270 "The gravitational acceleration of the Earth.", &
271 units="m s-2", default = 9.80, scale=us%m_to_L**2*us%Z_to_m*us%T_to_s**2)
272 call get_param(param_file, mdl, "RHO_0", cs%Rho0, &
273 "The mean ocean density used with BOUSSINESQ true to "//&
274 "calculate accelerations and the mass for conservation "//&
275 "properties, or with BOUSSINESQ false to convert some "//&
276 "parameters from vertical units of m to kg m-2.", &
277 units="kg m-3", default=1035.0, scale=us%kg_m3_to_R)
278 call get_param(param_file, mdl, "GUST_CONST", cs%gust_const, &
279 "The background gustiness in the winds.", &
280 units="Pa", default=0.0, scale=us%Pa_to_RLZ_T2*us%L_to_Z)
281
282 call get_param(param_file, mdl, "RESTOREBUOY", cs%restorebuoy, &
283 "If true, the buoyancy fluxes drive the model back "//&
284 "toward some specified surface state with a rate "//&
285 "given by FLUXCONST.", default= .false.)
286 if (cs%restorebuoy) then
287 call get_param(param_file, mdl, "FLUXCONST", cs%Flux_const, &
288 "The constant that relates the restoring surface fluxes to the relative "//&
289 "surface anomalies (akin to a piston velocity). Note the non-MKS units.", &
290 default=0.0, units="m day-1", scale=us%m_to_Z/(86400.0*us%s_to_T))
291 endif
292 call get_param(param_file, mdl, "RESTORE_FLUX_RHO", cs%rho_restore, &
293 "The density that is used to convert piston velocities into salt or heat "//&
294 "fluxes with RESTORE_SALINITY or RESTORE_TEMPERATURE.", &
295 units="kg m-3", default=cs%Rho0*us%R_to_kg_m3, scale=us%kg_m3_to_R, &
296 do_not_log=(cs%Flux_const==0.0).or.(.not.cs%restorebuoy))
297
298end subroutine user_surface_forcing_init
299
300!! \namespace user_surface_forcing
301!!
302!! This file contains the subroutines that a user should modify to
303!! to set the surface wind stresses and fluxes of buoyancy or
304!! temperature and fresh water. They are called when the run-time
305!! parameters WIND_CONFIG or BUOY_CONFIG are set to "USER". The
306!! standard version has simple examples, along with run-time error
307!! messages that will cause the model to abort if this code has no
308!! been modified. This code is intended for use with relatively
309!! simple specifications of the forcing. For more complicated forms,
310!! it is probably a good idea to read the forcing from input files
311!! using "file" for WIND_CONFIG and BUOY_CONFIG.
312!!
313!! USER_wind_forcing() should set the surface wind stresses (taux and
314!! tauy) perhaps along with the surface friction velocity (ustar).
315!!
316!! USER_buoyancy() forcing is used to set the surface buoyancy
317!! forcing, which may include a number of fresh water flux fields
318!! (evap, lprec, fprec, lrunoff, frunoff, and
319!! vprec) and the surface heat fluxes (sw, lw, latent and sens)
320!! if temperature and salinity are state variables, or it may simply
321!! be the buoyancy flux if it is not. This routine also has coded a
322!! restoring to surface values of temperature and salinity.
323
324end module user_surface_forcing