MESO_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!> Sets forcing for the MESO configuration
6module meso_surface_forcing
7
8use mom_diag_mediator, only : post_data, query_averaging_enabled
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, log_version, param_file_type
13use mom_forcing_type, only : forcing, mech_forcing
14use mom_forcing_type, only : allocate_forcing_type
15use mom_grid, only : ocean_grid_type
16use mom_io, only : file_exists, mom_read_data, slasher
17use mom_time_manager, only : time_type, operator(+), operator(/)
18use mom_tracer_flow_control, only : call_tracer_set_forcing
19use mom_tracer_flow_control, only : tracer_flow_control_cs
20use mom_unit_scaling, only : unit_scale_type
21use mom_variables, only : surface
22
23implicit none ; private
24
26
27!> This control structure is used to store parameters associated with the MESO forcing.
28type, public :: meso_surface_forcing_cs ; private
29
30 logical :: use_temperature !< If true, temperature and salinity are used as state variables.
31 logical :: restorebuoy !< If true, use restoring surface buoyancy forcing.
32 real :: rho0 !< The density used in the Boussinesq approximation [R ~> kg m-3].
33 real :: g_earth !< The gravitational acceleration [L2 Z-1 T-2 ~> m s-2].
34 real :: flux_const !< The restoring rate at the surface [Z T-1 ~> m s-1].
35 real :: rho_restore !< The density that is used to convert piston velocities into salt
36 !! or heat fluxes with salinity or temperature restoring [R ~> kg m-3]
37 real :: gust_const !< A constant unresolved background gustiness
38 !! that contributes to ustar [R L Z T-2 ~> Pa]
39 real, dimension(:,:), pointer :: &
40 t_restore(:,:) => null(), & !< The temperature to restore the SST toward [C ~> degC].
41 s_restore(:,:) => null(), & !< The salinity to restore the sea surface salnity toward [S ~> ppt]
42 pme(:,:) => null(), & !< The prescribed precip minus evap [Z T-1 ~> m s-1].
43 solar(:,:) => null() !< The shortwave forcing into the ocean [Q R Z T-1 ~> W m-2].
44 real, dimension(:,:), pointer :: heat(:,:) => null() !< The prescribed longwave, latent and sensible
45 !! heat flux into the ocean [Q R Z T-1 ~> W m-2].
46 character(len=200) :: inputdir !< The directory where NetCDF input files are.
47 character(len=200) :: salinityrestore_file !< The file with the target sea surface salinity
48 character(len=200) :: sstrestore_file !< The file with the target sea surface temperature
49 character(len=200) :: solar_file !< The file with the shortwave forcing
50 character(len=200) :: heating_file !< The file with the longwave, latent, and sensible heating
51 character(len=200) :: pme_file !< The file with precipitation minus evaporation
52 type(diag_ctrl), pointer :: diag !< A structure that is used to regulate the
53 !! timing of diagnostic output.
54end type meso_surface_forcing_cs
55
56logical :: first_call = .true. !< True until after the first call to the MESO forcing routines
57
58contains
59
60!> This subroutine sets up the MESO buoyancy forcing, which uses control-theory style
61!! specification restorative buoyancy fluxes at large scales.
62subroutine meso_buoyancy_forcing(sfc_state, fluxes, day, dt, G, US, CS)
63 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
64 !! describe the surface state of the ocean.
65 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
66 type(time_type), intent(in) :: day !< The time of the fluxes
67 real, intent(in) :: dt !< The amount of time over which
68 !! the fluxes apply [T ~> s]
69 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
70 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
71 type(meso_surface_forcing_cs), pointer :: cs !< A pointer to the control structure returned by
72 !! a previous call to MESO_surface_forcing_init
73
74! When temperature is used, there are long list of fluxes that need to be
75! set - essentially the same as for a full coupled model, but most of these
76! can be simply set to zero. The net fresh water flux should probably be
77! set in fluxes%evap and fluxes%lprec, with any salinity restoring
78! appearing in fluxes%vprec, and the other water flux components
79! (fprec, lrunoff and frunoff) left as arrays full of zeros.
80! Evap is usually negative and precip is usually positive. All heat fluxes
81! are in W m-2 and positive for heat going into the ocean. All fresh water
82! fluxes are in kg m-2 s-1 and positive for water moving into the ocean.
83
84 real :: density_restore ! The potential density that is being restored toward [R ~> kg m-3].
85 real :: rhoxcp ! The mean density times the heat capacity [Q R C-1 ~> J m-3 degC-1].
86 real :: buoy_rest_const ! A constant relating density anomalies to the
87 ! restoring buoyancy flux [L2 T-3 R-1 ~> m5 s-3 kg-1].
88
89 integer :: i, j, is, ie, js, je
90 integer :: isd, ied, jsd, jed
91
92 is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
93 isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
94
95 ! When modifying the code, comment out this error message. It is here
96 ! so that the original (unmodified) version is not accidentally used.
97
98 ! Allocate and zero out the forcing arrays, as necessary. This portion is
99 ! usually not changed.
100 if (cs%use_temperature) then
101 call safe_alloc_ptr(fluxes%evap, isd, ied, jsd, jed)
102 call safe_alloc_ptr(fluxes%lprec, isd, ied, jsd, jed)
103 call safe_alloc_ptr(fluxes%fprec, isd, ied, jsd, jed)
104 call safe_alloc_ptr(fluxes%lrunoff, isd, ied, jsd, jed)
105 call safe_alloc_ptr(fluxes%frunoff, isd, ied, jsd, jed)
106 call safe_alloc_ptr(fluxes%vprec, isd, ied, jsd, jed)
107
108 call safe_alloc_ptr(fluxes%sw, isd, ied, jsd, jed)
109 call safe_alloc_ptr(fluxes%lw, isd, ied, jsd, jed)
110 call safe_alloc_ptr(fluxes%latent, isd, ied, jsd, jed)
111 call safe_alloc_ptr(fluxes%sens, isd, ied, jsd, jed)
112 call safe_alloc_ptr(fluxes%heat_content_lprec, isd, ied, jsd, jed)
113 else ! This is the buoyancy only mode.
114 call safe_alloc_ptr(fluxes%buoy, isd, ied, jsd, jed)
115 endif
116
117
118 ! MODIFY THE CODE IN THE FOLLOWING LOOPS TO SET THE BUOYANCY FORCING TERMS.
119 if (cs%restorebuoy .and. first_call) then !#CTRL# .or. associated(CS%ctrl_forcing_CSp)) then
120 call safe_alloc_ptr(cs%T_Restore, isd, ied, jsd, jed)
121 call safe_alloc_ptr(cs%S_Restore, isd, ied, jsd, jed)
122 call safe_alloc_ptr(cs%Heat, isd, ied, jsd, jed)
123 call safe_alloc_ptr(cs%PmE, isd, ied, jsd, jed)
124 call safe_alloc_ptr(cs%Solar, isd, ied, jsd, jed)
125
126 call mom_read_data(trim(cs%inputdir)//trim(cs%SSTrestore_file), "SST", &
127 cs%T_Restore(:,:), g%Domain, scale=us%degC_to_C)
128 call mom_read_data(trim(cs%inputdir)//trim(cs%salinityrestore_file), "SAL", &
129 cs%S_Restore(:,:), g%Domain, scale=us%ppt_to_S)
130 call mom_read_data(trim(cs%inputdir)//trim(cs%heating_file), "Heat", &
131 cs%Heat(:,:), g%Domain, scale=us%W_m2_to_QRZ_T)
132 call mom_read_data(trim(cs%inputdir)//trim(cs%PmE_file), "PmE", &
133 cs%PmE(:,:), g%Domain, scale=us%m_to_Z*us%T_to_s)
134 call mom_read_data(trim(cs%inputdir)//trim(cs%Solar_file), "NET_SOL", &
135 cs%Solar(:,:), g%Domain, scale=us%W_m2_to_QRZ_T)
136 first_call = .false.
137 endif
138
139 if ( cs%use_temperature ) then
140 ! Set whichever fluxes are to be used here. Any fluxes that
141 ! are always zero do not need to be changed here.
142 do j=js,je ; do i=is,ie
143 ! Fluxes of fresh water through the surface are in units of [R Z T-1 ~> kg m-2 s-1]
144 ! and are positive downward - i.e. evaporation should be negative.
145 fluxes%evap(i,j) = -0.0 * g%mask2dT(i,j)
146 fluxes%lprec(i,j) = cs%PmE(i,j) * cs%Rho0 * g%mask2dT(i,j)
147
148 ! vprec will be set later, if it is needed for salinity restoring.
149 fluxes%vprec(i,j) = 0.0
150
151 ! Heat fluxes are in units of [Q R Z T-1 ~> W m-2] and are positive into the ocean.
152 fluxes%lw(i,j) = 0.0 * g%mask2dT(i,j)
153 fluxes%latent(i,j) = 0.0 * g%mask2dT(i,j)
154 fluxes%sens(i,j) = cs%Heat(i,j) * g%mask2dT(i,j)
155 fluxes%sw(i,j) = cs%Solar(i,j) * g%mask2dT(i,j)
156 enddo ; enddo
157 else ! This is the buoyancy only mode.
158 do j=js,je ; do i=is,ie
159 ! fluxes%buoy is the buoyancy flux into the ocean [L2 T-3 ~> m2 s-3]. A positive
160 ! buoyancy flux is of the same sign as heating the ocean.
161 fluxes%buoy(i,j) = 0.0 * g%mask2dT(i,j)
162 enddo ; enddo
163 endif
164
165 if (cs%restorebuoy) then
166 if (cs%use_temperature) then
167 call safe_alloc_ptr(fluxes%heat_added, isd, ied, jsd, jed)
168 ! When modifying the code, comment out this error message. It is here
169 ! so that the original (unmodified) version is not accidentally used.
170! call MOM_error(FATAL, "MESO_buoyancy_surface_forcing: " // &
171! "Temperature and salinity restoring used without modification." )
172
173 rhoxcp = cs%rho_restore * fluxes%C_p
174 do j=js,je ; do i=is,ie
175 ! Set Temp_restore and Salin_restore to the temperature (in degC) and
176 ! salinity (in ppt or PSU) that are being restored toward.
177 if (g%mask2dT(i,j) > 0.0) then
178 fluxes%heat_added(i,j) = g%mask2dT(i,j) * &
179 ((cs%T_Restore(i,j) - sfc_state%SST(i,j)) * rhoxcp * cs%Flux_const)
180 fluxes%vprec(i,j) = - (cs%rho_restore * cs%Flux_const) * &
181 (cs%S_Restore(i,j) - sfc_state%SSS(i,j)) / &
182 (0.5*(sfc_state%SSS(i,j) + cs%S_Restore(i,j)))
183 else
184 fluxes%heat_added(i,j) = 0.0
185 fluxes%vprec(i,j) = 0.0
186 endif
187 enddo ; enddo
188 else
189 ! When modifying the code, comment out this error message. It is here
190 ! so that the original (unmodified) version is not accidentally used.
191 call mom_error(fatal, "MESO_buoyancy_surface_forcing: " // &
192 "Buoyancy restoring used without modification." )
193
194 ! The -1 is because density has the opposite sign to buoyancy.
195 buoy_rest_const = -1.0 * (cs%G_Earth * cs%Flux_const) / cs%rho_restore
196 do j=js,je ; do i=is,ie
197 ! Set density_restore to an expression for the surface potential
198 ! density [R ~> kg m-3] that is being restored toward.
199 density_restore = 1030.0 * us%kg_m3_to_R
200
201 fluxes%buoy(i,j) = g%mask2dT(i,j) * buoy_rest_const * &
202 (density_restore - sfc_state%sfc_density(i,j))
203 enddo ; enddo
204 endif
205 endif ! end RESTOREBUOY
206
207end subroutine meso_buoyancy_forcing
208
209!> Initialize the MESO surface forcing module
210subroutine meso_surface_forcing_init(Time, G, US, param_file, diag, CS)
211
212 type(time_type), intent(in) :: time !< The current model time
213 type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
214 type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
215 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
216 type(diag_ctrl), target, intent(inout) :: diag !< structure used to regulate diagnostic output
217 type(meso_surface_forcing_cs), pointer :: cs !< A pointer that is set to point to the
218 !! control structure for this module
219
220 ! This include declares and sets the variable "version".
221# include "version_variable.h"
222 character(len=40) :: mdl = "MESO_surface_forcing" ! This module's name.
223
224 if (associated(cs)) then
225 call mom_error(warning, "MESO_surface_forcing_init called with an associated "// &
226 "control structure.")
227 return
228 endif
229 allocate(cs)
230 cs%diag => diag
231
232 ! Read all relevant parameters and write them to the model log.
233 call log_version(param_file, mdl, version, "")
234 call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", cs%use_temperature, &
235 "If true, Temperature and salinity are used as state "//&
236 "variables.", default=.true.)
237
238 call get_param(param_file, mdl, "G_EARTH", cs%G_Earth, &
239 "The gravitational acceleration of the Earth.", &
240 units="m s-2", default = 9.80, scale=us%m_to_L**2*us%Z_to_m*us%T_to_s**2)
241 call get_param(param_file, mdl, "RHO_0", cs%Rho0, &
242 "The mean ocean density used with BOUSSINESQ true to "//&
243 "calculate accelerations and the mass for conservation "//&
244 "properties, or with BOUSSINESQ false to convert some "//&
245 "parameters from vertical units of m to kg m-2.", &
246 units="kg m-3", default=1035.0, scale=us%kg_m3_to_R)
247 call get_param(param_file, mdl, "GUST_CONST", cs%gust_const, &
248 "The background gustiness in the winds.", units="Pa", default=0.0, &
249 scale=us%Pa_to_RLZ_T2)
250
251 call get_param(param_file, mdl, "RESTOREBUOY", cs%restorebuoy, &
252 "If true, the buoyancy fluxes drive the model back "//&
253 "toward some specified surface state with a rate "//&
254 "given by FLUXCONST.", default= .false.)
255
256 if (cs%restorebuoy) then
257 call get_param(param_file, mdl, "FLUXCONST", cs%Flux_const, &
258 "The constant that relates the restoring surface fluxes to the relative "//&
259 "surface anomalies (akin to a piston velocity). Note the non-MKS units.", &
260 default=0.0, units="m day-1", scale=us%m_to_Z/(86400.0*us%s_to_T))
261
262 call get_param(param_file, mdl, "SSTRESTORE_FILE", cs%SSTrestore_file, &
263 "The file with the SST toward which to restore in "//&
264 "variable TEMP.", fail_if_missing=.true.)
265 call get_param(param_file, mdl, "SALINITYRESTORE_FILE", cs%salinityrestore_file, &
266 "The file with the surface salinity toward which to "//&
267 "restore in variable SALT.", fail_if_missing=.true.)
268 call get_param(param_file, mdl, "SENSIBLEHEAT_FILE", cs%heating_file, &
269 "The file with the non-shortwave heat flux in "//&
270 "variable Heat.", fail_if_missing=.true.)
271 call get_param(param_file, mdl, "PRECIP_FILE", cs%PmE_file, &
272 "The file with the net precipiation minus evaporation "//&
273 "in variable PmE.", fail_if_missing=.true.)
274 call get_param(param_file, mdl, "SHORTWAVE_FILE", cs%Solar_file, &
275 "The file with the shortwave heat flux in "//&
276 "variable NET_SOL.", fail_if_missing=.true.)
277 call get_param(param_file, mdl, "INPUTDIR", cs%inputdir, default=".")
278 cs%inputdir = slasher(cs%inputdir)
279 call get_param(param_file, mdl, "RESTORE_FLUX_RHO", cs%rho_restore, &
280 "The density that is used to convert piston velocities into salt or heat "//&
281 "fluxes with RESTORE_SALINITY or RESTORE_TEMPERATURE.", &
282 units="kg m-3", default=cs%Rho0*us%R_to_kg_m3, scale=us%kg_m3_to_R, &
283 do_not_log=(cs%Flux_const==0.0).or.(.not.cs%restorebuoy))
284 endif
285
286end subroutine meso_surface_forcing_init
287
288!> \namespace meso_surface_forcing
289!!
290!! Rewritten by Robert Hallberg, June 2009
291!!
292!! This file contains the subroutines that a user should modify to
293!! to set the surface wind stresses and fluxes of buoyancy or
294!! temperature and fresh water. They are called when the run-time
295!! parameters WIND_CONFIG or BUOY_CONFIG are set to "USER". The
296!! standard version has simple examples, along with run-time error
297!! messages that will cause the model to abort if this code has not
298!! been modified. This code is intended for use with relatively
299!! simple specifications of the forcing. For more complicated forms,
300!! it is probably a good idea to read the forcing from input files
301!! using "file" for WIND_CONFIG and BUOY_CONFIG.
302!!
303!! MESO_buoyancy forcing is used to set the surface buoyancy
304!! forcing, which may include a number of fresh water flux fields
305!! (evap, liq_precip, froz_precip, liq_runoff, froz_runoff, and
306!! vprec) and the surface heat fluxes (sw, lw, latent and sens)
307!! if temperature and salinity are state variables, or it may simply
308!! be the buoyancy flux if it is not. This routine also has coded a
309!! restoring to surface values of temperature and salinity.
310
311end module meso_surface_forcing