← back to index

config_src/drivers/solo_driver/MOM_surface_forcing.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

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!> Functions that calculate the surface wind stresses and fluxes of buoyancy
6!! or temperature/salinity and fresh water, in ocean-only (solo) mode.
7!!
8!! These functions are called every time step, even if the wind stresses
9!! or buoyancy fluxes are constant in time - in that case these routines
10!! return quickly without doing anything. In addition, any I/O of forcing
11!! fields is controlled by surface_forcing_init, located in this file.
12module MOM_surface_forcing
13
14use MOM_constants, only : hlv, hlf
15use MOM_cpu_clock, only : cpu_clock_id, cpu_clock_begin, cpu_clock_end
16use MOM_cpu_clock, only : CLOCK_MODULE
17use MOM_data_override, only : data_override_init, data_override
18use MOM_diag_mediator, only : post_data, query_averaging_enabled
19use MOM_diag_mediator, only : diag_ctrl, safe_alloc_ptr
20use MOM_domains, only : pass_var, pass_vector, AGRID, To_South, To_West, To_All
21use MOM_domains, only : fill_symmetric_edges, CGRID_NE
22use MOM_error_handler, only : MOM_error, FATAL, WARNING, MOM_mesg, is_root_pe
23use MOM_error_handler, only : callTree_enter, callTree_leave
24use MOM_file_parser, only : get_param, log_param, log_version, param_file_type
25use MOM_string_functions, only : uppercase
26use MOM_forcing_type, only : forcing, mech_forcing
27use MOM_forcing_type, only : set_net_mass_forcing, copy_common_forcing_fields
28use MOM_forcing_type, only : set_derived_forcing_fields
29use MOM_forcing_type, only : forcing_diags, mech_forcing_diags, register_forcing_type_diags
30use MOM_forcing_type, only : allocate_forcing_type, deallocate_forcing_type
31use MOM_forcing_type, only : allocate_mech_forcing, deallocate_mech_forcing
32use MOM_grid, only : ocean_grid_type
33use MOM_get_input, only : Get_MOM_Input, directories
34use MOM_io, only : file_exists, MOM_read_data, MOM_read_vector, slasher
35use MOM_io, only : read_netCDF_data, EAST_FACE, NORTH_FACE, num_timelevels
36use MOM_restart, only : register_restart_field, restart_init, MOM_restart_CS
37use MOM_restart, only : restart_init_end, save_restart, restore_state
38use MOM_time_manager, only : time_type, operator(+), operator(/), operator(*)
39use MOM_time_manager, only : set_time, get_time, get_date, time_to_real
40use MOM_tracer_flow_control, only : call_tracer_set_forcing, tracer_flow_control_CS
41use MOM_unit_scaling, only : unit_scale_type
42use MOM_variables, only : surface
43use MESO_surface_forcing, only : MESO_buoyancy_forcing
44use MESO_surface_forcing, only : MESO_surface_forcing_init, MESO_surface_forcing_CS
45use user_surface_forcing, only : USER_wind_forcing, USER_buoyancy_forcing
46use user_surface_forcing, only : USER_surface_forcing_init, user_surface_forcing_CS
47use user_revise_forcing, only : user_alter_forcing, user_revise_forcing_init
48use user_revise_forcing, only : user_revise_forcing_CS
49use idealized_hurricane, only : idealized_hurricane_wind_forcing
50use idealized_hurricane, only : idealized_hurricane_wind_init, idealized_hurricane_CS
51use SCM_CVmix_tests, only : SCM_CVmix_tests_surface_forcing_init
52use SCM_CVmix_tests, only : SCM_CVmix_tests_wind_forcing
53use SCM_CVmix_tests, only : SCM_CVmix_tests_buoyancy_forcing
54use SCM_CVmix_tests, only : SCM_CVmix_tests_CS
55use BFB_surface_forcing, only : BFB_buoyancy_forcing
56use BFB_surface_forcing, only : BFB_surface_forcing_init, BFB_surface_forcing_CS
57use dumbbell_surface_forcing, only : dumbbell_surface_forcing_init, dumbbell_surface_forcing_CS
58use dumbbell_surface_forcing, only : dumbbell_buoyancy_forcing
59use MARBL_forcing_mod, only : marbl_forcing_CS, MARBL_forcing_init
60use MARBL_forcing_mod, only : convert_driver_fields_to_forcings
61
62implicit none ; private
63
64#include <MOM_memory.h>
65
66public set_forcing
67public surface_forcing_init
68public forcing_save_restart
69
70!> Structure containing pointers to the forcing fields that may be used to drive MOM.
71!! All fluxes are positive into the ocean.
72type, public :: surface_forcing_CS ; private
73
74 logical :: use_temperature !< if true, temp & salinity used as state variables
75 logical :: restorebuoy !< if true, use restoring surface buoyancy forcing
76 logical :: adiabatic !< if true, no diapycnal mass fluxes or surface buoyancy forcing
77 logical :: nonBous !< If true, this run is fully non-Boussinesq
78 logical :: variable_winds !< if true, wind stresses vary with time
79 logical :: variable_buoyforce !< if true, buoyancy forcing varies with time.
80 real :: south_lat !< southern latitude of the domain [degrees_N] or [km] or [m]
81 real :: len_lat !< domain length in latitude [degrees_N] or [km] or [m]
82
83 real :: Rho0 !< Boussinesq reference density [R ~> kg m-3]
84 real :: G_Earth !< gravitational acceleration [L2 Z-1 T-2 ~> m s-2]
85 real :: Flux_const = 0.0 !< piston velocity for surface restoring [Z T-1 ~> m s-1]
86 real :: Flux_const_T = 0.0 !< piston velocity for surface temperature restoring [Z T-1 ~> m s-1]
87 real :: Flux_const_S = 0.0 !< piston velocity for surface salinity restoring [Z T-1 ~> m s-1]
88 real :: rho_restore !< The density that is used to convert piston velocities into salt
89 !! or heat fluxes with salinity or temperature restoring [R ~> kg m-3]
90 real :: latent_heat_fusion !< latent heat of fusion times [Q ~> J kg-1]
91 real :: latent_heat_vapor !< latent heat of vaporization [Q ~> J kg-1]
92 real :: tau_x0 !< Constant zonal wind stress used in the WIND_CONFIG="const"
93 !! forcing [R L Z T-2 ~> Pa]
94 real :: tau_y0 !< Constant meridional wind stress used in the WIND_CONFIG="const"
95 !! forcing [R L Z T-2 ~> Pa]
96 real :: taux_mag !< Peak magnitude of the zonal wind stress for several analytic
97 !! profiles [R L Z T-2 ~> Pa]
98
99 real :: gust_const !< constant unresolved background gustiness for ustar [R Z2 T-2 ~> Pa]
100 logical :: read_gust_2d !< if true, use 2-dimensional gustiness supplied from a file
101 real, pointer :: gust(:,:) => NULL() !< spatially varying unresolved background gustiness [R L Z T-2 ~> Pa]
102 !! gust is used when read_gust_2d is true.
103
104 real, pointer :: T_Restore(:,:) => NULL() !< temperature to damp (restore) the SST to [C ~> degC]
105 real, pointer :: S_Restore(:,:) => NULL() !< salinity to damp (restore) the SSS [S ~> ppt]
106 real, pointer :: Dens_Restore(:,:) => NULL() !< density to damp (restore) surface density [R ~> kg m-3]
107
108 ! if WIND_CONFIG=='gyres' then use the following as = A, B, C and n respectively for
109 ! taux = A + B*sin(n*pi*y/L) + C*cos(n*pi*y/L)
110 real :: gyres_taux_const !< A constant wind stress [R L Z T-2 ~> Pa].
111 real :: gyres_taux_sin_amp !< The amplitude of cosine wind stress gyres [R L Z T-2 ~> Pa], if WIND_CONFIG=='gyres'
112 real :: gyres_taux_cos_amp !< The amplitude of cosine wind stress gyres [R L Z T-2 ~> Pa], if WIND_CONFIG=='gyres'
113 real :: gyres_taux_n_pis !< The number of sine lobes in the basin if WIND_CONFIG=='gyres' [nondim]
114 integer :: answer_date !< This 8-digit integer gives the approximate date with which the order
115 !! of arithmetic and expressions were added to the code.
116 !! Dates before 20190101 use original answers.
117 !! Dates after 20190101 use a form of the gyre wind stresses that are
118 !! rotationally invariant and more likely to be the same between compilers.
119 logical :: ustar_gustless_bug !< If true, include a bug in the time-averaging of the
120 !! gustless wind friction velocity.
121 logical :: use_marbl_tracers !< If true, allocate memory for forcing needed by MARBL
122 ! if WIND_CONFIG=='scurves' then use the following to define a piecewise scurve profile
123 real :: scurves_ydata(20) = 90. !< Latitudes of scurve nodes [degreesN]
124 real :: scurves_taux(20) = 0. !< Zonal wind stress values at scurve nodes [R L Z T-2 ~> Pa]
125
126 real :: T_north !< Target temperatures at north used in buoyancy_forcing_linear [C ~> degC]
127 real :: T_south !< Target temperatures at south used in buoyancy_forcing_linear [C ~> degC]
128 real :: S_north !< Target salinity at north used in buoyancy_forcing_linear [S ~> ppt]
129 real :: S_south !< Target salinity at south used in buoyancy_forcing_linear [S ~> ppt]
130
131 logical :: first_call_set_forcing = .true. !< True until after the first call to set_forcing
132 logical :: archaic_OMIP_file = .true. !< If true use the variable names and data fields from
133 !! a very old version of the OMIP forcing
134 logical :: dataOverrideIsInitialized = .false. !< If true, data override has been initialized
135
136 real :: wind_scale !< value by which wind-stresses are scaled [nondim]
137 real :: constantHeatForcing !< value used for sensible heat flux when buoy_config="const" [Q R Z T-1 ~> W m-2]
138
139 character(len=8) :: wind_stagger !< A character indicating how the wind stress components
140 !! are staggered in WIND_FILE. Valid values are A or C for now.
141 type(tracer_flow_control_CS), pointer :: tracer_flow_CSp => NULL() !< A pointer to the structure
142 !! that is used to orchestrate the calling of tracer packages
143!#CTRL# type(ctrl_forcing_CS), pointer :: ctrl_forcing_CSp => NULL()
144 type(MOM_restart_CS), pointer :: restart_CSp => NULL() !< A pointer to the restart control structure
145
146 type(diag_ctrl), pointer :: diag !< structure used to regulate timing of diagnostic output
147
148 character(len=200) :: inputdir !< directory where NetCDF input files are.
149 character(len=200) :: wind_config !< indicator for wind forcing type (2gyre, USER, FILE..)
150 character(len=200) :: wind_file !< if wind_config is "file", file to use
151 character(len=200) :: buoy_config !< indicator for buoyancy forcing type
152
153 character(len=200) :: longwave_file = '' !< The file from which the longwave heat flux is read
154 character(len=200) :: shortwave_file = '' !< The file from which the shortwave heat flux is read
155 character(len=200) :: evaporation_file = '' !< The file from which the evaporation is read
156 character(len=200) :: sensibleheat_file = '' !< The file from which the sensible heat flux is read
157 character(len=200) :: latentheat_file = '' !< The file from which the latent heat flux is read
158
159 character(len=200) :: rain_file = '' !< The file from which the rainfall is read
160 character(len=200) :: snow_file = '' !< The file from which the snowfall is read
161 character(len=200) :: runoff_file = '' !< The file from which the runoff is read
162
163 character(len=200) :: longwaveup_file = '' !< The file from which the upward longwave heat flux is read
164 character(len=200) :: shortwaveup_file = '' !< The file from which the upward shortwave heat flux is read
165
166 character(len=200) :: SSTrestore_file = '' !< The file from which to read the sea surface
167 !! temperature to restore toward
168 character(len=200) :: salinityrestore_file = '' !< The file from which to read the sea surface
169 !! salinity to restore toward
170
171 character(len=80) :: stress_x_var = '' !< X-wind stress variable name in the input file
172 character(len=80) :: stress_y_var = '' !< Y-wind stress variable name in the input file
173 character(len=80) :: ustar_var = '' !< ustar variable name in the input file
174 character(len=80) :: LW_var = '' !< longwave heat flux variable name in the input file
175 character(len=80) :: SW_var = '' !< shortwave heat flux variable name in the input file
176 character(len=80) :: latent_var = '' !< latent heat flux variable name in the input file
177 character(len=80) :: sens_var = '' !< sensible heat flux variable name in the input file
178 character(len=80) :: evap_var = '' !< evaporation variable name in the input file
179 character(len=80) :: rain_var = '' !< rainfall variable name in the input file
180 character(len=80) :: snow_var = '' !< snowfall variable name in the input file
181 character(len=80) :: lrunoff_var = '' !< liquid runoff variable name in the input file
182 character(len=80) :: frunoff_var = '' !< frozen runoff variable name in the input file
183 character(len=80) :: SST_restore_var = '' !< target sea surface temperature variable name in the input file
184 character(len=80) :: SSS_restore_var = '' !< target sea surface salinity variable name in the input file
185
186 ! These variables relate model times to time levels in the various forcing files.
187 integer :: wind_days_per_rec = 0 !< If positive the number of days of wind stress per forcing file time level,
188 !! or if negative the number of time levels per day. If 31 change forcing
189 !! monthly, or if 0 the model will guess the right value based on the file size.
190 integer :: SW_days_per_rec = 0 !< If positive the number of days shortwave heat flux per forcing file time level,
191 !! or if negative the number of time levels per day. If 31 change forcing
192 !! monthly, or if 0 the model will guess the right value based on the file size.
193 integer :: LW_days_per_rec = 0 !< If positive the number of days longwave heat flux per forcing file time level,
194 !! or if negative the number of time levels per day. If 31 change forcing
195 !! monthly, or if 0 the model will guess the right value based on the file size.
196 integer :: latent_days_per_rec = 0 !< If positive the number of days latent heat flux per forcing file time level,
197 !! or if negative the number of time levels per day. If 31 change forcing
198 !! monthly, or if 0 the model will guess the right value based on the file size.
199 integer :: sens_days_per_rec = 0 !< If positive the number of days sensible heat flux per forcing file time level,
200 !! or if negative the number of time levels per day. If 31 change forcing
201 !! monthly, or if 0 the model will guess the right value based on the file size.
202 integer :: evap_days_per_rec = 0 !< If positive the number of days evaporation per forcing file time level,
203 !! or if negative the number of time levels per day. If 31 change forcing
204 !! monthly, or if 0 the model will guess the right value based on the file size.
205 integer :: precip_days_per_rec = 0 !< If positive the number of days precipitation per forcing file time level,
206 !! or if negative the number of time levels per day. If 31 change forcing
207 !! monthly, or if 0 the model will guess the right value based on the file size.
208 integer :: runoff_days_per_rec = 0 !< If positive the number of days runoff per forcing file time level,
209 !! or if negative the number of time levels per day. If 31 change forcing
210 !! monthly, or if 0 the model will guess the right value based on the file size.
211 integer :: SST_days_per_rec = 0 !< If positive the number of days target SST per forcing file time level,
212 !! or if negative the number of time levels per day. If 31 change forcing
213 !! monthly, or if 0 the model will guess the right value based on the file size.
214 integer :: SSS_days_per_rec = 0 !< If positive the number of days target SSS per forcing file time level,
215 !! or if negative the number of time levels per day. If 31 change forcing
216 !! monthly, or if 0 the model will guess the right value based on the file size.
217
218 ! These variables give the number of time levels in the various forcing files.
219 integer :: wind_nlev = -1 !< The number of time levels in the file of wind stress
220 integer :: SW_nlev = -1 !< The number of time levels in the file of shortwave heat flux
221 integer :: LW_nlev = -1 !< The number of time levels in the file of longwave heat flux
222 integer :: latent_nlev = -1 !< The number of time levels in the file of latent heat flux
223 integer :: sens_nlev = -1 !< The number of time levels in the file of sensible heat flux
224 integer :: evap_nlev = -1 !< The number of time levels in the file of evaporation
225 integer :: precip_nlev = -1 !< The number of time levels in the file of precipitation
226 integer :: runoff_nlev = -1 !< The number of time levels in the file of runoff
227 integer :: SST_nlev = -1 !< The number of time levels in the file of target SST
228 integer :: SSS_nlev = -1 !< The number of time levels in the file of target SSS
229
230 ! These variables give the last time level read for the various forcing files.
231 integer :: wind_last_lev = -1 !< The last time level read of wind stress
232 integer :: SW_last_lev = -1 !< The last time level read of shortwave heat flux
233 integer :: LW_last_lev = -1 !< The last time level read of longwave heat flux
234 integer :: latent_last_lev = -1 !< The last time level read of latent heat flux
235 integer :: sens_last_lev = -1 !< The last time level read of sensible heat flux
236 integer :: evap_last_lev = -1 !< The last time level read of evaporation
237 integer :: precip_last_lev = -1 !< The last time level read of precipitation
238 integer :: runoff_last_lev = -1 !< The last time level read of runoff
239 integer :: SST_last_lev = -1 !< The last time level read of target SST
240 integer :: SSS_last_lev = -1 !< The last time level read of target SSS
241
242 type(forcing_diags), public :: handles !< A structure with diagnostics handles
243
244 !>@{ Control structures for named forcing packages
245 type(user_revise_forcing_CS), pointer :: urf_CS => NULL()
246 type(user_surface_forcing_CS), pointer :: user_forcing_CSp => NULL()
247 type(BFB_surface_forcing_CS), pointer :: BFB_forcing_CSp => NULL()
248 type(dumbbell_surface_forcing_CS), pointer :: dumbbell_forcing_CSp => NULL()
249 type(MESO_surface_forcing_CS), pointer :: MESO_forcing_CSp => NULL()
250 type(idealized_hurricane_CS), pointer :: idealized_hurricane_CSp => NULL()
251 type(SCM_CVmix_tests_CS), pointer :: SCM_CVmix_tests_CSp => NULL()
252 type(marbl_forcing_CS), pointer :: marbl_forcing_CSp => NULL()
253 !>@}
254
255end type surface_forcing_CS
256
257integer :: id_clock_forcing !< A CPU time clock
258
259contains
260
261!> Calls subroutines in this file to get surface forcing fields.
262!!
263!! It also allocates and initializes the fields in the forcing and mech_forcing types
264!! the first time it is called.
26512subroutine set_forcing(sfc_state, forces, fluxes, day_start, day_interval, G, US, CS)
266 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
267 !! describe the surface state of the ocean.
268 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
269 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
270 type(time_type), intent(in) :: day_start !< The start time of the fluxes
271 type(time_type), intent(in) :: day_interval !< Length of time over which these fluxes applied
272 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
273 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
274 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
275 !! a previous surface_forcing_init call
276 ! Local variables
277 real :: dt ! length of time over which fluxes applied [T ~> s]
278 type(time_type) :: day_center ! central time of the fluxes.
279 integer :: isd, ied, jsd, jed
28012 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
281
28212 call cpu_clock_begin(id_clock_forcing)
28312 call callTree_enter("set_forcing, MOM_surface_forcing.F90")
284
28512 day_center = day_start + day_interval/2
28612 dt = time_to_real(day_interval, scale=US%s_to_T)
287
28812 if (CS%first_call_set_forcing) then
289 ! Allocate memory for the mechanical and thermodynamic forcing fields.
2901 call allocate_mech_forcing(G, forces, stress=.true., ustar=.not.CS%nonBous, press=.true., tau_mag=CS%nonBous)
291
292 call allocate_forcing_type(G, fluxes, ustar=.not.CS%nonBous, marbl=CS%use_marbl_tracers, tau_mag=CS%nonBous, &
2931 fix_accum_bug=.not.CS%ustar_gustless_bug)
2941 if (trim(CS%buoy_config) /= "NONE") then
2951 if ( CS%use_temperature ) then
2961 call allocate_forcing_type(G, fluxes, water=.true., heat=.true., press=.true.)
2971 if (CS%restorebuoy) then
2981 call safe_alloc_ptr(CS%T_Restore,isd, ied, jsd, jed)
2991 call safe_alloc_ptr(fluxes%heat_added, isd, ied, jsd, jed)
3001 call safe_alloc_ptr(CS%S_Restore, isd, ied, jsd, jed)
301 endif
302 else ! CS%use_temperature false.
3030 call safe_alloc_ptr(fluxes%buoy, isd, ied, jsd, jed)
304
3050 if (CS%restorebuoy) call safe_alloc_ptr(CS%Dens_Restore, isd, ied, jsd, jed)
306 endif ! endif for CS%use_temperature
307 endif
308 endif
309
310 ! calls to various wind options
31112 if (CS%variable_winds .or. CS%first_call_set_forcing) then
312
31312 if (trim(CS%wind_config) == "file") then
3140 call wind_forcing_from_file(sfc_state, forces, day_center, G, US, CS)
31512 elseif (trim(CS%wind_config) == "data_override") then
3160 call wind_forcing_by_data_override(sfc_state, forces, day_center, G, US, CS)
31712 elseif (trim(CS%wind_config) == "2gyre") then
3180 call wind_forcing_2gyre(sfc_state, forces, day_center, G, US, CS)
31912 elseif (trim(CS%wind_config) == "1gyre") then
3200 call wind_forcing_1gyre(sfc_state, forces, day_center, G, US, CS)
32112 elseif (trim(CS%wind_config) == "gyres") then
32212 call wind_forcing_gyres(sfc_state, forces, day_center, G, US, CS)
3230 elseif (trim(CS%wind_config) == "zero") then
3240 call wind_forcing_const(sfc_state, forces, 0., 0., day_center, G, US, CS)
3250 elseif (trim(CS%wind_config) == "const") then
3260 call wind_forcing_const(sfc_state, forces, CS%tau_x0, CS%tau_y0, day_center, G, US, CS)
3270 elseif (trim(CS%wind_config) == "Neverworld" .or. trim(CS%wind_config) == "Neverland") then
3280 call Neverworld_wind_forcing(sfc_state, forces, day_center, G, US, CS)
3290 elseif (trim(CS%wind_config) == "scurves") then
3300 call scurve_wind_forcing(sfc_state, forces, day_center, G, US, CS)
3310 elseif (trim(CS%wind_config) == "ideal_hurr") then
3320 call idealized_hurricane_wind_forcing(sfc_state, forces, day_center, G, US, CS%idealized_hurricane_CSp)
3330 elseif (trim(CS%wind_config) == "SCM_ideal_hurr") then
334 call MOM_error(FATAL, "MOM_surface_forcing (set_forcing): "//&
3350 'WIND_CONFIG = "SCM_ideal_hurr" is a depricated option.')
3360 elseif (trim(CS%wind_config) == "SCM_CVmix_tests") then
3370 call SCM_CVmix_tests_wind_forcing(sfc_state, forces, day_center, G, US, CS%SCM_CVmix_tests_CSp)
3380 elseif (trim(CS%wind_config) == "USER") then
3390 call USER_wind_forcing(sfc_state, forces, day_center, G, US, CS%user_forcing_CSp)
3400 elseif (CS%variable_winds .and. .not.CS%first_call_set_forcing) then
341 call MOM_error(FATAL, &
3420 "MOM_surface_forcing: Variable winds defined with no wind config")
343 else
344 call MOM_error(FATAL, &
3450 "MOM_surface_forcing:Unrecognized wind config "//trim(CS%wind_config))
346 endif
347 endif
348
349 ! calls to various buoyancy forcing options
35012 if (CS%restorebuoy .and. .not.CS%variable_buoyforce) then
351 call MOM_error(FATAL, "With RESTOREBUOY = True, VARIABLE_BUOYFORCE = True should be used. "//&
352 "Otherwise, this can lead to diverging solutions when a simulation "//&
3530 "is continued using a restart file.")
354 endif
355
35612 if ((CS%variable_buoyforce .or. CS%first_call_set_forcing) .and. &
357 (.not.CS%adiabatic)) then
35812 if (trim(CS%buoy_config) == "file") then
3590 call buoyancy_forcing_from_files(sfc_state, fluxes, day_center, dt, G, US, CS)
36012 elseif (trim(CS%buoy_config) == "data_override") then
3610 call buoyancy_forcing_from_data_override(sfc_state, fluxes, day_center, dt, G, US, CS)
36212 elseif (trim(CS%buoy_config) == "zero") then
3630 call buoyancy_forcing_zero(sfc_state, fluxes, day_center, dt, G, CS)
36412 elseif (trim(CS%buoy_config) == "const") then
3650 call buoyancy_forcing_const(sfc_state, fluxes, day_center, dt, G, US, CS)
36612 elseif (trim(CS%buoy_config) == "linear") then
36712 call buoyancy_forcing_linear(sfc_state, fluxes, day_center, dt, G, US, CS)
3680 elseif (trim(CS%buoy_config) == "MESO") then
3690 call MESO_buoyancy_forcing(sfc_state, fluxes, day_center, dt, G, US, CS%MESO_forcing_CSp)
3700 elseif (trim(CS%buoy_config) == "SCM_CVmix_tests") then
3710 call SCM_CVmix_tests_buoyancy_forcing(sfc_state, fluxes, day_center, G, US, CS%SCM_CVmix_tests_CSp)
3720 elseif (trim(CS%buoy_config) == "USER") then
3730 call USER_buoyancy_forcing(sfc_state, fluxes, day_center, dt, G, US, CS%user_forcing_CSp)
3740 elseif (trim(CS%buoy_config) == "BFB") then
3750 call BFB_buoyancy_forcing(sfc_state, fluxes, day_center, dt, G, US, CS%BFB_forcing_CSp)
3760 elseif (trim(CS%buoy_config) == "dumbbell") then
3770 call dumbbell_buoyancy_forcing(sfc_state, fluxes, day_center, dt, G, US, CS%dumbbell_forcing_CSp)
3780 elseif (trim(CS%buoy_config) == "NONE") then
3790 call MOM_mesg("MOM_surface_forcing: buoyancy forcing has been set to omitted.")
3800 elseif (CS%variable_buoyforce .and. .not.CS%first_call_set_forcing) then
381 call MOM_error(FATAL, &
3820 "MOM_surface_forcing: Variable buoy defined with no buoy config.")
383 else
384 call MOM_error(FATAL, &
3850 "MOM_surface_forcing: Unrecognized buoy config "//trim(CS%buoy_config))
386 endif
387 endif
388
38912 if (CS%use_marbl_tracers) then
3900 call MARBL_forcing_from_data_override(fluxes, day_center, G, US, CS)
391 endif
392
39312 if (associated(CS%tracer_flow_CSp)) then
394 call call_tracer_set_forcing(sfc_state, fluxes, day_start, day_interval, G, US, CS%Rho0, &
39512 CS%tracer_flow_CSp)
396 endif
397
398 ! Allow for user-written code to alter the fluxes after all the above
39912 call user_alter_forcing(sfc_state, fluxes, day_center, G, CS%urf_CS)
400
401 ! Fields that exist in both the forcing and mech_forcing types must be copied.
40212 if (CS%variable_winds .or. CS%first_call_set_forcing) then
40312 call copy_common_forcing_fields(forces, fluxes, G)
40412 call set_derived_forcing_fields(forces, fluxes, G, US, CS%Rho0)
405 endif
406
40712 if ((CS%variable_buoyforce .or. CS%first_call_set_forcing) .and. &
408 (.not.CS%adiabatic)) then
40912 call set_net_mass_forcing(fluxes, forces, G, US)
410 endif
411
41212 CS%first_call_set_forcing = .false.
413
41412 call cpu_clock_end(id_clock_forcing)
41512 call callTree_leave("set_forcing")
416
41712end subroutine set_forcing
418
419!> Sets the surface wind stresses to constant values
4200subroutine wind_forcing_const(sfc_state, forces, tau_x0, tau_y0, day, G, US, CS)
421 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
422 !! describe the surface state of the ocean.
423 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
424 real, intent(in) :: tau_x0 !< The zonal wind stress [R Z L T-2 ~> Pa]
425 real, intent(in) :: tau_y0 !< The meridional wind stress [R Z L T-2 ~> Pa]
426 type(time_type), intent(in) :: day !< The time of the fluxes
427 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
428 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
429 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
430 !! a previous surface_forcing_init call
431 ! Local variables
432 real :: mag_tau ! Magnitude of the wind stress [R Z2 T-2 ~> Pa]
433 integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq
434
4350 call callTree_enter("wind_forcing_const, MOM_surface_forcing.F90")
4360 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
4370 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
438
4390 mag_tau = US%L_to_Z * sqrt( tau_x0**2 + tau_y0**2)
440
441 ! Set the steady surface wind stresses, in units of [R L Z T-2 ~> Pa].
4420 do j=js,je ; do I=is-1,Ieq
4430 forces%taux(I,j) = tau_x0
444 enddo ; enddo
445
4460 do J=js-1,Jeq ; do i=is,ie
4470 forces%tauy(i,J) = tau_y0
448 enddo ; enddo
449
4500 if (CS%read_gust_2d) then
4510 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
4520 forces%ustar(i,j) = sqrt( ( mag_tau + CS%gust(i,j) ) / CS%Rho0 )
453 enddo ; enddo ; endif
4540 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
4550 forces%tau_mag(i,j) = mag_tau + CS%gust(i,j)
456 enddo ; enddo ; endif
457 else
4580 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
4590 forces%ustar(i,j) = sqrt( ( mag_tau + CS%gust_const ) / CS%Rho0 )
460 enddo ; enddo ; endif
4610 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
4620 forces%tau_mag(i,j) = mag_tau + CS%gust_const
463 enddo ; enddo ; endif
464 endif
465
4660 call callTree_leave("wind_forcing_const")
4670end subroutine wind_forcing_const
468
469
470!> Sets the surface wind stresses to set up two idealized gyres.
4710subroutine wind_forcing_2gyre(sfc_state, forces, day, G, US, CS)
472 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
473 !! describe the surface state of the ocean.
474 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
475 type(time_type), intent(in) :: day !< The time of the fluxes
476 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
477 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
478 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
479 !! a previous surface_forcing_init call
480 ! Local variables
481 real :: PI ! A common irrational number, 3.1415926535... [nondim]
482 integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq
483
4840 call callTree_enter("wind_forcing_2gyre, MOM_surface_forcing.F90")
4850 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
4860 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
487
4880 PI = 4.0*atan(1.0)
489
490 ! Set the steady surface wind stresses, in units of [R L Z T-2 ~> Pa].
4910 do j=js,je ; do I=is-1,Ieq
4920 forces%taux(I,j) = CS%taux_mag * (1.0 - cos(2.0*PI*(G%geoLatCu(I,j)-CS%South_lat) / CS%len_lat))
493 enddo ; enddo
494
4950 do J=js-1,Jeq ; do i=is,ie
4960 forces%tauy(i,J) = 0.0
497 enddo ; enddo
498
4990 if (associated(forces%ustar)) call stresses_to_ustar(forces, G, US, CS)
500
5010 call callTree_leave("wind_forcing_2gyre")
5020end subroutine wind_forcing_2gyre
503
504
505!> Sets the surface wind stresses to set up a single idealized gyre.
5060subroutine wind_forcing_1gyre(sfc_state, forces, day, G, US, CS)
507 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
508 !! describe the surface state of the ocean.
509 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
510 type(time_type), intent(in) :: day !< The time of the fluxes
511 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
512 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
513 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
514 !! a previous surface_forcing_init call
515 ! Local variables
516 real :: PI ! A common irrational number, 3.1415926535... [nondim]
517 integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq
518
5190 call callTree_enter("wind_forcing_1gyre, MOM_surface_forcing.F90")
5200 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
5210 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
522
5230 PI = 4.0*atan(1.0)
524
525 ! Set the steady surface wind stresses, in units of [R Z L T-2 ~> Pa].
5260 do j=js,je ; do I=is-1,Ieq
5270 forces%taux(I,j) = CS%taux_mag * cos(PI*(G%geoLatCu(I,j)-CS%South_lat)/CS%len_lat)
528 enddo ; enddo
529
5300 do J=js-1,Jeq ; do i=is,ie
5310 forces%tauy(i,J) = 0.0
532 enddo ; enddo
533
5340 if (associated(forces%ustar)) call stresses_to_ustar(forces, G, US, CS)
535
5360 call callTree_leave("wind_forcing_1gyre")
5370end subroutine wind_forcing_1gyre
538
539!> Sets the surface wind stresses to set up idealized gyres.
54012subroutine wind_forcing_gyres(sfc_state, forces, day, G, US, CS)
541 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
542 !! describe the surface state of the ocean.
543 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
544 type(time_type), intent(in) :: day !< The time of the fluxes
545 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
546 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
547 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
548 !! a previous surface_forcing_init call
549 ! Local variables
550 real :: PI ! A common irrational number, 3.1415926535... [nondim]
551 real :: y ! The latitude relative to the south normalized by the domain extent [nondim]
552 integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq
553
55412 call callTree_enter("wind_forcing_gyres, MOM_surface_forcing.F90")
55512 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
55612 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
557
55812 PI = 4.0*atan(1.0)
559
560 ! steady surface wind stresses [R L Z T-2 ~> Pa]
56190780 do j=js-1,je+1 ; do I=is-1,Ieq
56290024 y = (G%geoLatCu(I,j)-CS%South_lat) / CS%len_lat
563 forces%taux(I,j) = CS%gyres_taux_const + &
564 ( CS%gyres_taux_sin_amp*sin(CS%gyres_taux_n_pis*PI*y) &
56590768 + CS%gyres_taux_cos_amp*cos(CS%gyres_taux_n_pis*PI*y) )
566 enddo ; enddo
567
56890048 do J=js-1,Jeq ; do i=is-1,ie+1
56990036 forces%tauy(i,J) = 0.0
570 enddo ; enddo
571
572 ! set the friction velocity
57312 if (CS%answer_date < 20190101) then
5740 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
575 forces%tau_mag(i,j) = CS%gust_const + US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
5760 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
577 enddo ; enddo ; endif
5780 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
579 forces%ustar(i,j) = sqrt( (CS%gust_const/CS%Rho0) + &
580 US%L_to_Z * sqrt(0.5*((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2) + &
5810 (forces%taux(I-1,j)**2) + (forces%taux(I,j)**2)))/CS%Rho0 )
582 enddo ; enddo ; endif
583 else
58412 call stresses_to_ustar(forces, G, US, CS)
585 endif
586
58712 call callTree_leave("wind_forcing_gyres")
58812end subroutine wind_forcing_gyres
589
590!> Sets the surface wind stresses, forces%taux and forces%tauy for the
591!! Neverworld forcing configuration.
5920subroutine Neverworld_wind_forcing(sfc_state, forces, day, G, US, CS)
593 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
594 !! describe the surface state of the ocean.
595 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
596 type(time_type), intent(in) :: day !< Time used for determining the fluxes.
597 type(ocean_grid_type), intent(inout) :: G !< Grid structure.
598 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
599 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
600 !! a previous surface_forcing_init call
601 ! Local variables
602 integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq
603 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
604 real :: PI ! A common irrational number, 3.1415926535... [nondim]
605 real :: y ! The latitude relative to the south normalized by the domain extent [nondim]
606 real :: tau_max ! The magnitude of the wind stress [R Z L T-2 ~> Pa]
607 real :: off ! An offset in the relative latitude [nondim]
608
6090 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
6100 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
6110 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
6120 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
613
614 ! Allocate the forcing arrays, if necessary.
6150 call allocate_mech_forcing(G, forces, stress=.true.)
616
617 ! Set the surface wind stresses, in units of [R Z L T-2 ~> Pa]. A positive taux
618 ! accelerates the ocean to the (pseudo-)east.
619
620 ! The i-loop extends to is-1 so that taux can be used later in the
621 ! calculation of ustar - otherwise the lower bound would be Isq.
6220 PI = 4.0*atan(1.0)
623
6240 forces%taux(:,:) = 0.0
6250 tau_max = CS%taux_mag
6260 off = 0.02
6270 do j=js,je ; do I=is-1,Ieq
6280 y = (G%geoLatT(i,j)-G%south_lat)/G%len_lat
629
6300 if (y <= 0.29) then
6310 forces%taux(I,j) = forces%taux(I,j) + tau_max * ( (1/0.29)*y - ( 1/(2*PI) )*sin( (2*PI*y) / 0.29 ) )
632 endif
6330 if ((y > 0.29) .and. (y <= (0.8-off))) then
6340 forces%taux(I,j) = forces%taux(I,j) + tau_max *(0.35+0.65*cos(PI*(y-0.29)/(0.51-off)) )
635 endif
6360 if ((y > (0.8-off)) .and. (y <= (1-off))) then
6370 forces%taux(I,j) = forces%taux(I,j) + tau_max *( 1.5*( (y-1+off) - (0.1/PI)*sin(10.0*PI*(y-0.8+off)) ) )
638 endif
6390 forces%taux(I,j) = G%mask2dCu(I,j) * forces%taux(I,j)
640 enddo ; enddo
641
6420 do J=js-1,Jeq ; do i=is,ie
6430 forces%tauy(i,J) = G%mask2dCv(i,J) * 0.0
644 enddo ; enddo
645
646 ! Set the surface friction velocity, in units of [Z T-1 ~> m s-1]. ustar is always positive.
6470 if (associated(forces%ustar)) call stresses_to_ustar(forces, G, US, CS)
648
6490end subroutine Neverworld_wind_forcing
650
651!> Sets the zonal wind stresses to a piecewise series of s-curves.
6520subroutine scurve_wind_forcing(sfc_state, forces, day, G, US, CS)
653 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
654 !! describe the surface state of the ocean.
655 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
656 type(time_type), intent(in) :: day !< Time used for determining the fluxes.
657 type(ocean_grid_type), intent(inout) :: G !< Grid structure.
658 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
659 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
660 !! a previous surface_forcing_init call
661 ! Local variables
662 integer :: i, j, kseg
663 real :: y_curve ! The latitude relative to the southern end of a curve segment [degreesN]
664 real :: L_curve ! The latitudinal extent of a curve segment [degreesN]
665! real :: ydata(7) = (/ -70., -45., -15., 0., 15., 45., 70. /)
666! real :: taudt(7) = (/ 0., 0.2, -0.1, -0.02, -0.1, 0.1, 0. /)
667
668 ! Allocate the forcing arrays, if necessary.
6690 call allocate_mech_forcing(G, forces, stress=.true.)
670
6710 kseg = 1
6720 do j=G%jsd,G%jed ; do I=G%IsdB,G%IedB
673 ! Find segment k s.t. ydata(k)<= G%geoLatCu(I,j) < ydata(k+1)
6740 do while (G%geoLatCu(I,j) >= CS%scurves_ydata(kseg+1) .and. kseg<6) ! Should this be kseg<19?
6750 kseg = kseg+1
676 enddo
6770 do while (G%geoLatCu(I,j) < CS%scurves_ydata(kseg) .and. kseg>1)
6780 kseg = kseg-1
679 enddo
680
6810 y_curve = G%geoLatCu(I,j) - CS%scurves_ydata(kseg)
6820 L_curve = CS%scurves_ydata(kseg+1) - CS%scurves_ydata(kseg)
683 forces%taux(I,j) = CS%scurves_taux(kseg) + &
6840 (CS%scurves_taux(kseg+1) - CS%scurves_taux(kseg)) * scurve(y_curve, L_curve)
6850 forces%taux(I,j) = G%mask2dCu(I,j) * forces%taux(I,j)
686 enddo ; enddo
687
6880 do J=G%JsdB,G%JedB ; do i=G%isd,G%ied
6890 forces%tauy(i,J) = G%mask2dCv(i,J) * 0.0
690 enddo ; enddo
691
692 ! Set the surface friction velocity, in units of [Z T-1 ~> m s-1]. ustar is always positive.
6930 if (associated(forces%ustar)) call stresses_to_ustar(forces, G, US, CS)
694
6950end subroutine scurve_wind_forcing
696
697!> Returns the value of a cosine-bell function evaluated at x/L
6980real function scurve(x,L)
699 real , intent(in) :: x !< non-dimensional position [nondim]
700 real , intent(in) :: L !< non-dimensional width [nondim]
701 real :: s ! The evaluated function value [nondim]
702
7030 s = x/L
7040 scurve = (3. - 2.*s) * (s*s)
7050end function scurve
706
707! Sets the surface wind stresses from input files.
7080subroutine wind_forcing_from_file(sfc_state, forces, day, G, US, CS)
709 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
710 !! describe the surface state of the ocean.
711 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
712 type(time_type), intent(in) :: day !< The time of the fluxes
713 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
714 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
715 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
716 !! a previous surface_forcing_init call
717 ! Local variables
718 character(len=200) :: filename ! The name of the input file.
7190 real :: temp_x(SZI_(G),SZJ_(G)) ! Pseudo-zonal wind stresses at h-points [R L Z T-2 ~> Pa]
7200 real :: temp_y(SZI_(G),SZJ_(G)) ! Pseudo-meridional wind stresses at h-points [R L Z T-2 ~> Pa]
7210 real :: ustar_loc(SZI_(G),SZJ_(G)) ! The local value of ustar [Z T-1 ~> m s-1]
722 real :: tau_mag ! The magnitude of the wind stress including any contributions from
723 ! sub-gridscale variability or gustiness [R Z2 T-2 ~> Pa]
724 integer :: time_lev ! The time level that is used for a field.
725 integer :: i, j, is, ie, js, je, Isq, Ieq, Jsq, Jeq
726 logical :: read_Ustar
727
7280 call callTree_enter("wind_forcing_from_file, MOM_surface_forcing.F90")
7290 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
7300 Isq = G%IscB ; Ieq = G%IecB ; Jsq = G%JscB ; Jeq = G%JecB
731
7320 time_lev = get_file_time_level(day, CS%wind_nlev, CS%wind_days_per_rec)
733
7340 if (time_lev /= CS%wind_last_lev) then
7350 filename = trim(CS%wind_file)
7360 read_Ustar = (len_trim(CS%ustar_var) > 0)
737! if (is_root_pe()) &
738! write(*,'("Wind_forcing Reading time level ",I," last was ",I,".")')&
739! time_lev-1,CS%wind_last_lev-1
7400 select case ( uppercase(CS%wind_stagger(1:1)) )
741 case ("A")
7420 temp_x(:,:) = 0.0 ; temp_y(:,:) = 0.0
743 call MOM_read_vector(filename, CS%stress_x_var, CS%stress_y_var, &
744 temp_x(:,:), temp_y(:,:), G%Domain, stagger=AGRID, &
7450 timelevel=time_lev, scale=US%Pa_to_RLZ_T2)
746
7470 call pass_vector(temp_x, temp_y, G%Domain, To_All, AGRID)
7480 do j=js,je ; do I=is-1,Ieq
7490 forces%taux(I,j) = 0.5 * CS%wind_scale * (temp_x(i,j) + temp_x(i+1,j))
750 enddo ; enddo
7510 do J=js-1,Jeq ; do i=is,ie
7520 forces%tauy(i,J) = 0.5 * CS%wind_scale * (temp_y(i,j) + temp_y(i,j+1))
753 enddo ; enddo
754
7550 if (.not.read_Ustar) then
7560 if (CS%read_gust_2d) then
7570 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
7580 forces%tau_mag(i,j) = CS%gust(i,j) + US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2))
759 enddo ; enddo ; endif
7600 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
7610 tau_mag = CS%gust(i,j) + US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2))
7620 forces%ustar(i,j) = sqrt(tau_mag / CS%Rho0)
763 enddo ; enddo ; endif
764 else
7650 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
7660 forces%tau_mag(i,j) = CS%gust_const + US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2))
767 enddo ; enddo ; endif
7680 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
769 forces%ustar(i,j) = sqrt( CS%gust_const/CS%Rho0 + &
7700 US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2)) / CS%Rho0 )
771 enddo ; enddo ; endif
772 endif
773 endif
774 case ("C")
7750 if (G%symmetric) then
7760 if (.not.associated(G%Domain_aux)) call MOM_error(FATAL, &
777 " wind_forcing_from_file with C-grid input and symmetric memory "//&
7780 " called with a non-associated auxiliary domain in the grid type.")
779 ! Read the data as though symmetric memory were not being used, and
780 ! then translate it appropriately.
7810 temp_x(:,:) = 0.0 ; temp_y(:,:) = 0.0
782 call MOM_read_vector(filename, CS%stress_x_var, CS%stress_y_var, &
783 temp_x(:,:), temp_y(:,:), &
784 G%Domain_aux, stagger=CGRID_NE, timelevel=time_lev, &
7850 scale=US%Pa_to_RLZ_T2)
7860 do j=js,je ; do i=is,ie
7870 forces%taux(I,j) = CS%wind_scale * temp_x(I,j)
7880 forces%tauy(i,J) = CS%wind_scale * temp_y(i,J)
789 enddo ; enddo
7900 call fill_symmetric_edges(forces%taux, forces%tauy, G%Domain, stagger=CGRID_NE)
791 else
792 call MOM_read_vector(filename, CS%stress_x_var, CS%stress_y_var, &
793 forces%taux(:,:), forces%tauy(:,:), &
794 G%Domain, stagger=CGRID_NE, timelevel=time_lev, &
7950 scale=US%Pa_to_RLZ_T2)
796
7970 if (CS%wind_scale /= 1.0) then
7980 do j=js,je ; do I=Isq,Ieq
7990 forces%taux(I,j) = CS%wind_scale * forces%taux(I,j)
800 enddo ; enddo
8010 do J=Jsq,Jeq ; do i=is,ie
8020 forces%tauy(i,J) = CS%wind_scale * forces%tauy(i,J)
803 enddo ; enddo
804 endif
805 endif
806
8070 call pass_vector(forces%taux, forces%tauy, G%Domain, To_All)
8080 if (.not.read_Ustar) then
8090 if (CS%read_gust_2d) then
8100 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
811 forces%tau_mag(i,j) = CS%gust(i,j) + &
812 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
8130 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
814 enddo ; enddo ; endif
8150 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
816 tau_mag = CS%gust(i,j) + &
817 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
8180 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
8190 forces%ustar(i,j) = sqrt( tau_mag / CS%Rho0 )
820 enddo ; enddo ; endif
821 else
8220 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
823 forces%tau_mag(i,j) = CS%gust_const + &
824 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
8250 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
826 enddo ; enddo ; endif
8270 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
828 forces%ustar(i,j) = sqrt( CS%gust_const/CS%Rho0 + &
829 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
8300 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))/CS%Rho0 )
831 enddo ; enddo ; endif
832 endif
833 endif
834 case default
835 call MOM_error(FATAL, "wind_forcing_from_file: Unrecognized stagger "//&
8360 trim(CS%wind_stagger)//" is not 'A' or 'C'.")
837 end select
838
8390 if (read_Ustar) then
840 call MOM_read_data(filename, CS%Ustar_var, ustar_loc(:,:), &
8410 G%Domain, timelevel=time_lev, scale=US%m_to_Z*US%T_to_s)
8420 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
8430 forces%tau_mag(i,j) = CS%Rho0 * ustar_loc(i,j)**2
844 enddo ; enddo ; endif
8450 if (associated(forces%ustar)) then ; do j=G%jsc,G%jec ; do i=G%isc,G%iec
8460 forces%ustar(i,j) = ustar_loc(i,j)
847 enddo ; enddo ; endif
848 endif
849
8500 CS%wind_last_lev = time_lev
851
852 endif ! time_lev /= CS%wind_last_lev
853
8540 call callTree_leave("wind_forcing_from_file")
8550end subroutine wind_forcing_from_file
856
857
858! Sets the surface wind stresses via the data override facility.
8590subroutine wind_forcing_by_data_override(sfc_state, forces, day, G, US, CS)
860 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
861 !! describe the surface state of the ocean.
862 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
863 type(time_type), intent(in) :: day !< The time of the fluxes
864 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
865 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
866 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
867 !! a previous surface_forcing_init call
868 ! Local variables
8690 real :: temp_x(SZI_(G),SZJ_(G)) ! Pseudo-zonal wind stresses at h-points [R Z L T-2 ~> Pa].
8700 real :: temp_y(SZI_(G),SZJ_(G)) ! Pseudo-meridional wind stresses at h-points [R Z L T-2 ~> Pa].
8710 real :: ustar_prev(SZI_(G),SZJ_(G)) ! The pre-override value of ustar [Z T-1 ~> m s-1]
8720 real :: ustar_loc(SZI_(G),SZJ_(G)) ! The value of ustar, perhaps altered by data override [Z T-1 ~> m s-1]
873 real :: tau_mag ! The magnitude of the wind stress including any contributions from
874 ! sub-gridscale variability or gustiness [R Z2 T-2 ~> Pa]
875 integer :: i, j
876
8770 call callTree_enter("wind_forcing_by_data_override, MOM_surface_forcing.F90")
878
8790 if (.not.CS%dataOverrideIsInitialized) then
8800 call allocate_mech_forcing(G, forces, stress=.true., ustar=.not.CS%nonBous, press=.true., tau_mag=CS%nonBous)
8810 call data_override_init(G%Domain)
8820 CS%dataOverrideIsInitialized = .True.
883 endif
884
8850 temp_x(:,:) = 0.0 ; temp_y(:,:) = 0.0
886 ! CS%wind_scale is ignored here because it is not set in this mode.
8870 call data_override(G%Domain, 'taux', temp_x, day, scale=US%Pa_to_RLZ_T2)
8880 call data_override(G%Domain, 'tauy', temp_y, day, scale=US%Pa_to_RLZ_T2)
8890 call pass_vector(temp_x, temp_y, G%Domain, To_All, AGRID)
8900 do j=G%jsc,G%jec ; do I=G%isc-1,G%IecB
8910 forces%taux(I,j) = 0.5 * (temp_x(i,j) + temp_x(i+1,j))
892 enddo ; enddo
8930 do J=G%jsc-1,G%JecB ; do i=G%isc,G%iec
8940 forces%tauy(i,J) = 0.5 * (temp_y(i,j) + temp_y(i,j+1))
895 enddo ; enddo
896
8970 if (CS%read_gust_2d) then
8980 call data_override(G%Domain, 'gust', CS%gust, day, scale=US%Pa_to_RLZ_T2*US%L_to_Z)
8990 if (associated(forces%tau_mag)) then ; do j=G%jsc,G%jec ; do i=G%isc,G%iec
9000 forces%tau_mag(i,j) = US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2)) + CS%gust(i,j)
901 enddo ; enddo ; endif
9020 do j=G%jsc,G%jec ; do i=G%isc,G%iec
9030 tau_mag = US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2)) + CS%gust(i,j)
9040 ustar_loc(i,j) = sqrt( tau_mag / CS%Rho0 )
905 enddo ; enddo
906 else
9070 if (associated(forces%tau_mag)) then
9080 do j=G%jsc,G%jec ; do i=G%isc,G%iec
9090 forces%tau_mag(i,j) = US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2)) + CS%gust_const
910 ! ustar_loc(i,j) = sqrt( forces%tau_mag(i,j) / CS%Rho0 )
911 enddo ; enddo
912 endif
9130 do j=G%jsc,G%jec ; do i=G%isc,G%iec
914 ustar_loc(i,j) = sqrt(US%L_to_Z * sqrt((temp_x(i,j)**2) + (temp_y(i,j)**2))/CS%Rho0 + &
9150 CS%gust_const/CS%Rho0)
916 enddo ; enddo
917 endif
918
919 ! Give the data override the option to modify the newly calculated forces%ustar.
9200 ustar_prev(:,:) = ustar_loc(:,:)
9210 call data_override(G%Domain, 'ustar', ustar_loc, day, scale=US%m_to_Z*US%T_to_s)
922
923 ! Only reset values where data override of ustar has occurred
9240 if (associated(forces%tau_mag)) then
9250 do j=G%jsc,G%jec ; do i=G%isc,G%iec ; if (ustar_prev(i,j) /= ustar_loc(i,j)) then
9260 forces%tau_mag(i,j) = CS%Rho0 * ustar_loc(i,j)**2
927 endif ; enddo ; enddo
928 endif
929
9300 if (associated(forces%ustar)) then ; do j=G%jsc,G%jec ; do i=G%isc,G%iec
9310 forces%ustar(i,j) = ustar_loc(i,j)
932 enddo ; enddo ; endif
933
9340 call pass_vector(forces%taux, forces%tauy, G%Domain, To_All)
935
9360 call callTree_leave("wind_forcing_by_data_override")
9370end subroutine wind_forcing_by_data_override
938
939!> Translate the wind stresses into the friction velocity, including effects of background gustiness.
94012subroutine stresses_to_ustar(forces, G, US, CS)
941 type(mech_forcing), intent(inout) :: forces !< A structure with the driving mechanical forces
942 type(ocean_grid_type), intent(in) :: G !< Grid structure.
943 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
944 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
945 !! a previous surface_forcing_init call
946 ! Local variables
947 real :: I_rho ! The inverse of the Boussinesq reference density [R-1 ~> m3 kg-1]
948 real :: tau_mag ! The magnitude of the wind stress including any contributions from
949 ! sub-gridscale variability or gustiness [R Z2 T-2 ~> Pa]
950 integer :: i, j, is, ie, js, je
951
95212 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
953
95412 I_rho = 1.0 / CS%Rho0
955
95612 if (CS%read_gust_2d) then
9570 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
958 forces%tau_mag(i,j) = CS%gust(i,j) + &
959 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
9600 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
961 enddo ; enddo ; endif
9620 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
963 tau_mag = CS%gust(i,j) + &
964 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
9650 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
9660 forces%ustar(i,j) = sqrt( tau_mag * I_rho )
967 enddo ; enddo ; endif
968 else
96987132 if (associated(forces%tau_mag)) then ; do j=js,je ; do i=is,ie
970 forces%tau_mag(i,j) = CS%gust_const + &
971 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
97287120 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
973 enddo ; enddo ; endif
97487132 if (associated(forces%ustar)) then ; do j=js,je ; do i=is,ie
975 tau_mag = CS%gust_const + &
976 US%L_to_Z * sqrt(0.5*(((forces%tauy(i,J-1)**2) + (forces%tauy(i,J)**2)) + &
97786400 ((forces%taux(I-1,j)**2) + (forces%taux(I,j)**2))))
97887120 forces%ustar(i,j) = sqrt( tau_mag * I_rho )
979 enddo ; enddo ; endif
980 endif
981
98212end subroutine stresses_to_ustar
983
984!> Specifies zero surface buoyancy fluxes from input files.
9850subroutine buoyancy_forcing_from_files(sfc_state, fluxes, day, dt, G, US, CS)
986 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
987 !! describe the surface state of the ocean.
988 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
989 type(time_type), intent(in) :: day !< The time of the fluxes
990 real, intent(in) :: dt !< The amount of time over which
991 !! the fluxes apply [T ~> s]
992 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
993 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
994 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
995 !! a previous surface_forcing_init call
996 ! Local variables
997 real, dimension(SZI_(G),SZJ_(G)) :: &
9980 temp ! A 2-d temporary work array in various units of [Q R Z T-1 ~> W m-2] or
999 ! [R Z T-1 ~> kg m-2 s-1]
1000!#CTRL# real, dimension(SZI_(G),SZJ_(G)) :: &
1001!#CTRL# SST_anom, & ! Instantaneous sea surface temperature anomalies from a
1002!#CTRL# ! target (observed) value [C ~> degC].
1003!#CTRL# SSS_anom, & ! Instantaneous sea surface salinity anomalies from a target
1004!#CTRL# ! (observed) value [S ~> ppt].
1005!#CTRL# SSS_mean ! A (mean?) salinity about which to normalize local salinity
1006!#CTRL# ! anomalies when calculating restorative precipitation anomalies [S ~> ppt].
1007
1008 real :: rhoXcp ! reference density times heat capacity [Q R C-1 ~> J m-3 degC-1]
1009
1010 logical :: fluxes_changed ! True if any of the fluxes might have been altered
1011 integer :: time_lev ! time level that for a field
1012
1013 integer :: i, j, is, ie, js, je
1014
10150 call callTree_enter("buoyancy_forcing_from_files, MOM_surface_forcing.F90")
1016
10170 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
1018
10190 if (CS%use_temperature) rhoXcp = CS%rho_restore * fluxes%C_p
1020
1021 ! Read the buoyancy forcing file
10220 fluxes_changed = .false.
1023
1024 ! longwave
10250 time_lev = get_file_time_level(day, CS%LW_nlev, CS%LW_days_per_rec)
10260 if (time_lev /= CS%LW_last_lev) then
1027 call MOM_read_data(CS%longwave_file, CS%LW_var, fluxes%lw(:,:), &
10280 G%Domain, timelevel=time_lev, scale=US%W_m2_to_QRZ_T)
10290 if (CS%archaic_OMIP_file) then
1030 call MOM_read_data(CS%longwaveup_file, "lwup_sfc", temp(:,:), G%Domain, &
10310 timelevel=time_lev, scale=US%W_m2_to_QRZ_T)
10320 do j=js,je ; do i=is,ie ; fluxes%LW(i,j) = fluxes%LW(i,j) - temp(i,j) ; enddo ; enddo
1033 endif
10340 CS%LW_last_lev = time_lev ; fluxes_changed = .true.
1035 endif
1036
1037 ! evaporation
10380 if ( (CS%evap_nlev /= CS%LW_nlev) .or. (CS%evap_days_per_rec /= CS%LW_days_per_rec) ) &
10390 time_lev = get_file_time_level(day, CS%evap_nlev, CS%evap_days_per_rec)
10400 if (time_lev /= CS%evap_last_lev) then
10410 if (CS%archaic_OMIP_file) then
1042 call MOM_read_data(CS%evaporation_file, CS%evap_var, fluxes%evap(:,:), &
10430 G%Domain, timelevel=time_lev, scale=-US%kg_m2s_to_RZ_T)
10440 do j=js,je ; do i=is,ie
10450 fluxes%latent(i,j) = CS%latent_heat_vapor*fluxes%evap(i,j)
10460 fluxes%latent_evap_diag(i,j) = fluxes%latent(i,j)
1047 enddo ; enddo
1048 else
1049 call MOM_read_data(CS%evaporation_file, CS%evap_var, fluxes%evap(:,:), &
10500 G%Domain, timelevel=time_lev, scale=US%kg_m2s_to_RZ_T)
1051 endif
10520 CS%evap_last_lev = time_lev ; fluxes_changed = .true.
1053 endif
1054
10550 if ( (CS%latent_nlev /= CS%evap_nlev) .or. (CS%latent_days_per_rec /= CS%evap_days_per_rec) ) &
10560 time_lev = get_file_time_level(day, CS%latent_nlev, CS%latent_days_per_rec)
10570 if (time_lev /= CS%latent_last_lev) then
10580 if (.not.CS%archaic_OMIP_file) then
1059 call MOM_read_data(CS%latentheat_file, CS%latent_var, fluxes%latent(:,:), &
10600 G%Domain, timelevel=time_lev, scale=US%W_m2_to_QRZ_T)
10610 do j=js,je ; do i=is,ie
10620 fluxes%latent_evap_diag(i,j) = fluxes%latent(i,j)
1063 enddo ; enddo
1064 endif
10650 CS%latent_last_lev = time_lev ; fluxes_changed = .true.
1066 endif
1067
10680 if ( (CS%sens_nlev /= CS%latent_nlev) .or. (CS%sens_days_per_rec /= CS%latent_days_per_rec) ) &
10690 time_lev = get_file_time_level(day, CS%sens_nlev, CS%sens_days_per_rec)
10700 if (time_lev /= CS%sens_last_lev) then
10710 if (CS%archaic_OMIP_file) then
1072 call MOM_read_data(CS%sensibleheat_file, CS%sens_var, fluxes%sens(:,:), &
10730 G%Domain, timelevel=time_lev, scale=-US%W_m2_to_QRZ_T)
1074 else
1075 call MOM_read_data(CS%sensibleheat_file, CS%sens_var, fluxes%sens(:,:), &
10760 G%Domain, timelevel=time_lev, scale=US%W_m2_to_QRZ_T)
1077 endif
10780 CS%sens_last_lev = time_lev ; fluxes_changed = .true.
1079 endif
1080
10810 if ( (CS%SW_nlev /= CS%sens_nlev) .or. (CS%SW_days_per_rec /= CS%sens_days_per_rec) ) &
10820 time_lev = get_file_time_level(day, CS%SW_nlev, CS%SW_days_per_rec)
10830 if (time_lev /= CS%SW_last_lev) then
1084 call MOM_read_data(CS%shortwave_file, CS%SW_var, fluxes%sw(:,:), G%Domain, &
10850 timelevel=time_lev, scale=US%W_m2_to_QRZ_T)
10860 if (CS%archaic_OMIP_file) then
1087 call MOM_read_data(CS%shortwaveup_file, "swup_sfc", temp(:,:), G%Domain, &
10880 timelevel=time_lev, scale=US%W_m2_to_QRZ_T)
10890 do j=js,je ; do i=is,ie
10900 fluxes%sw(i,j) = fluxes%sw(i,j) - temp(i,j)
1091 enddo ; enddo
1092 endif
10930 CS%SW_last_lev = time_lev ; fluxes_changed = .true.
1094 endif
1095
10960 if ( (CS%precip_nlev /= CS%SW_nlev) .or. (CS%precip_days_per_rec /= CS%SW_days_per_rec) ) &
10970 time_lev = get_file_time_level(day, CS%precip_nlev, CS%precip_days_per_rec)
10980 if (time_lev /= CS%precip_last_lev) then
1099 call MOM_read_data(CS%snow_file, CS%snow_var, &
11000 fluxes%fprec(:,:), G%Domain, timelevel=time_lev, scale=US%kg_m2s_to_RZ_T)
1101 call MOM_read_data(CS%rain_file, CS%rain_var, &
11020 fluxes%lprec(:,:), G%Domain, timelevel=time_lev, scale=US%kg_m2s_to_RZ_T)
11030 if (CS%archaic_OMIP_file) then
11040 do j=js,je ; do i=is,ie
11050 fluxes%lprec(i,j) = fluxes%lprec(i,j) - fluxes%fprec(i,j)
1106 enddo ; enddo
1107 endif
11080 CS%precip_last_lev = time_lev ; fluxes_changed = .true.
1109 endif
1110
11110 if ( (CS%runoff_nlev /= CS%precip_nlev) .or. (CS%runoff_days_per_rec /= CS%precip_days_per_rec) ) &
11120 time_lev = get_file_time_level(day, CS%runoff_nlev, CS%runoff_days_per_rec)
11130 if (time_lev /= CS%runoff_last_lev) then
11140 if (CS%archaic_OMIP_file) then
1115 call MOM_read_data(CS%runoff_file, CS%lrunoff_var, temp(:,:), &
11160 G%Domain, timelevel=time_lev, scale=US%kg_m2s_to_RZ_T*US%m_to_L**2)
11170 do j=js,je ; do i=is,ie
11180 fluxes%lrunoff(i,j) = temp(i,j)*G%IareaT(i,j)
1119 enddo ; enddo
1120 call MOM_read_data(CS%runoff_file, CS%frunoff_var, temp(:,:), &
11210 G%Domain, timelevel=time_lev, scale=US%kg_m2s_to_RZ_T*US%m_to_L**2)
11220 do j=js,je ; do i=is,ie
11230 fluxes%frunoff(i,j) = temp(i,j)*G%IareaT(i,j)
1124 enddo ; enddo
1125 else
1126 call MOM_read_data(CS%runoff_file, CS%lrunoff_var, fluxes%lrunoff(:,:), &
11270 G%Domain, timelevel=time_lev, scale=US%kg_m2s_to_RZ_T)
1128 call MOM_read_data(CS%runoff_file, CS%frunoff_var, fluxes%frunoff(:,:), &
11290 G%Domain, timelevel=time_lev, scale=US%kg_m2s_to_RZ_T)
1130 endif
11310 CS%runoff_last_lev = time_lev ; fluxes_changed = .true.
1132 endif
1133
1134 ! Read the SST and SSS fields for damping.
11350 if (CS%restorebuoy) then !#CTRL# .or. associated(CS%ctrl_forcing_CSp)) then
11360 time_lev = get_file_time_level(day, CS%SST_nlev, CS%SST_days_per_rec)
11370 if (time_lev /= CS%SST_last_lev) then
1138 call MOM_read_data(CS%SSTrestore_file, CS%SST_restore_var, &
11390 CS%T_Restore(:,:), G%Domain, timelevel=time_lev, scale=US%degC_to_C)
11400 CS%SST_last_lev = time_lev
1141 endif
1142
11430 if ( (CS%SSS_nlev /= CS%SST_nlev) .or. (CS%SSS_days_per_rec /= CS%SST_days_per_rec) ) &
11440 time_lev = get_file_time_level(day, CS%SSS_nlev, CS%SSS_days_per_rec)
11450 if (time_lev /= CS%SSS_last_lev) then
1146 call MOM_read_data(CS%salinityrestore_file, CS%SSS_restore_var, &
11470 CS%S_Restore(:,:), G%Domain, timelevel=time_lev, scale=US%ppt_to_S)
11480 CS%SSS_last_lev = time_lev
1149 endif
1150 endif
1151
11520 if (fluxes_changed) then
1153 ! mask out land points and compute heat content of water fluxes
1154 ! assume liquid precipitation enters ocean at SST
1155 ! assume frozen precipitation enters ocean at 0degC
1156 ! assume liquid runoff enters ocean at SST
1157 ! assume solid runoff (calving) enters ocean at 0degC
1158 ! mass leaving the ocean has heat_content determined in MOM_diabatic_driver.F90
11590 do j=js,je ; do i=is,ie
11600 fluxes%evap(i,j) = fluxes%evap(i,j) * G%mask2dT(i,j)
11610 fluxes%lprec(i,j) = fluxes%lprec(i,j) * G%mask2dT(i,j)
11620 fluxes%fprec(i,j) = fluxes%fprec(i,j) * G%mask2dT(i,j)
11630 fluxes%lrunoff(i,j) = fluxes%lrunoff(i,j) * G%mask2dT(i,j)
11640 fluxes%frunoff(i,j) = fluxes%frunoff(i,j) * G%mask2dT(i,j)
11650 fluxes%lw(i,j) = fluxes%lw(i,j) * G%mask2dT(i,j)
11660 fluxes%sens(i,j) = fluxes%sens(i,j) * G%mask2dT(i,j)
11670 fluxes%sw(i,j) = fluxes%sw(i,j) * G%mask2dT(i,j)
11680 fluxes%latent(i,j) = fluxes%latent(i,j) * G%mask2dT(i,j)
1169
11700 fluxes%latent_evap_diag(i,j) = fluxes%latent_evap_diag(i,j) * G%mask2dT(i,j)
11710 fluxes%latent_fprec_diag(i,j) = -fluxes%fprec(i,j)*CS%latent_heat_fusion
11720 fluxes%latent_frunoff_diag(i,j) = -fluxes%frunoff(i,j)*CS%latent_heat_fusion
1173 enddo ; enddo
1174 endif ! fluxes have changed and need to be masked
1175
1176
1177 ! restoring surface boundary fluxes
11780 if (CS%restorebuoy) then
1179
11800 if (CS%use_temperature) then
11810 do j=js,je ; do i=is,ie
11820 if (G%mask2dT(i,j) > 0.0) then
1183 fluxes%heat_added(i,j) = G%mask2dT(i,j) * &
11840 ((CS%T_Restore(i,j) - sfc_state%SST(i,j)) * rhoXcp * CS%Flux_const_T)
1185 fluxes%vprec(i,j) = - (CS%rho_restore*CS%Flux_const_S) * &
1186 (CS%S_Restore(i,j) - sfc_state%SSS(i,j)) / &
11870 (0.5*(sfc_state%SSS(i,j) + CS%S_Restore(i,j)))
1188 else
11890 fluxes%heat_added(i,j) = 0.0
11900 fluxes%vprec(i,j) = 0.0
1191 endif
1192 enddo ; enddo
1193 else
11940 do j=js,je ; do i=is,ie
11950 if (G%mask2dT(i,j) > 0.0) then
1196 fluxes%buoy(i,j) = (CS%Dens_Restore(i,j) - sfc_state%sfc_density(i,j)) * &
11970 (CS%G_Earth * CS%Flux_const / CS%rho_restore)
1198 else
11990 fluxes%buoy(i,j) = 0.0
1200 endif
1201 enddo ; enddo
1202 endif
1203
1204 else ! not RESTOREBUOY
12050 if (.not.CS%use_temperature) then
1206 call MOM_error(FATAL, "buoyancy_forcing in MOM_surface_forcing: "// &
12070 "The fluxes need to be defined without RESTOREBUOY.")
1208 endif
1209
1210 endif ! end RESTOREBUOY
1211
1212!#CTRL# if (associated(CS%ctrl_forcing_CSp)) then
1213!#CTRL# do j=js,je ; do i=is,ie
1214!#CTRL# SST_anom(i,j) = sfc_state%SST(i,j) - CS%T_Restore(i,j)
1215!#CTRL# SSS_anom(i,j) = sfc_state%SSS(i,j) - CS%S_Restore(i,j)
1216!#CTRL# SSS_mean(i,j) = 0.5*(sfc_state%SSS(i,j) + CS%S_Restore(i,j))
1217!#CTRL# enddo ; enddo
1218!#CTRL# call apply_ctrl_forcing(SST_anom, SSS_anom, SSS_mean, fluxes%heat_added, &
1219!#CTRL# fluxes%vprec, day, dt, G, US, CS%ctrl_forcing_CSp)
1220!#CTRL# endif
1221
12220 call callTree_leave("buoyancy_forcing_from_files")
12230end subroutine buoyancy_forcing_from_files
1224
1225!> Specifies zero surface buoyancy fluxes from data over-ride.
12260subroutine buoyancy_forcing_from_data_override(sfc_state, fluxes, day, dt, G, US, CS)
1227 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
1228 !! describe the surface state of the ocean.
1229 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
1230 type(time_type), intent(in) :: day !< The time of the fluxes
1231 real, intent(in) :: dt !< The amount of time over which
1232 !! the fluxes apply [T ~> s]
1233 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
1234 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1235 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
1236 !! a previous surface_forcing_init call
1237 ! Local variables
1238!#CTRL# real, dimension(SZI_(G),SZJ_(G)) :: &
1239!#CTRL# SST_anom, & ! Instantaneous sea surface temperature anomalies from a
1240!#CTRL# ! target (observed) value [C ~> degC].
1241!#CTRL# SSS_anom, & ! Instantaneous sea surface salinity anomalies from a target
1242!#CTRL# ! (observed) value [S ~> ppt].
1243!#CTRL# SSS_mean ! A (mean?) salinity about which to normalize local salinity
1244!#CTRL# ! anomalies when calculating restorative precipitation anomalies [S ~> ppt].
1245 real :: rhoXcp ! The mean density times the heat capacity [Q R C-1 ~> J m-3 degC-1].
1246 integer :: i, j, is, ie, js, je, isd, ied, jsd, jed
1247
12480 call callTree_enter("buoyancy_forcing_from_data_override, MOM_surface_forcing.F90")
1249
12500 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
12510 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
1252
12530 if (CS%use_temperature) rhoXcp = CS%rho_restore * fluxes%C_p
1254
12550 if (.not.CS%dataOverrideIsInitialized) then
12560 call data_override_init(G%Domain)
12570 CS%dataOverrideIsInitialized = .True.
1258 endif
1259
12600 call data_override(G%Domain, 'lw', fluxes%lw, day, scale=US%W_m2_to_QRZ_T)
12610 call data_override(G%Domain, 'sw', fluxes%sw, day, scale=US%W_m2_to_QRZ_T)
1262
1263 ! The normal MOM6 sign conventions are that fluxes%evap and fluxes%sens are positive into the
1264 ! ocean but evap and sens are normally positive quantities in the files.
12650 call data_override(G%Domain, 'evap', fluxes%evap, day, scale=-US%kg_m2s_to_RZ_T)
12660 call data_override(G%Domain, 'sens', fluxes%sens, day, scale=-US%W_m2_to_QRZ_T)
1267
12680 do j=js,je ; do i=is,ie
12690 fluxes%latent(i,j) = CS%latent_heat_vapor*fluxes%evap(i,j)
12700 fluxes%latent_evap_diag(i,j) = fluxes%latent(i,j)
1271 enddo ; enddo
1272
12730 call data_override(G%Domain, 'snow', fluxes%fprec, day, scale=US%kg_m2s_to_RZ_T)
12740 call data_override(G%Domain, 'rain', fluxes%lprec, day, scale=US%kg_m2s_to_RZ_T)
12750 call data_override(G%Domain, 'runoff', fluxes%lrunoff, day, scale=US%kg_m2s_to_RZ_T)
12760 call data_override(G%Domain, 'calving', fluxes%frunoff, day, scale=US%kg_m2s_to_RZ_T)
1277
1278! Read the SST and SSS fields for damping.
12790 if (CS%restorebuoy) then !#CTRL# .or. associated(CS%ctrl_forcing_CSp)) then
12800 call data_override(G%Domain, 'SST_restore', CS%T_restore, day, scale=US%degC_to_C)
12810 call data_override(G%Domain, 'SSS_restore', CS%S_restore, day, scale=US%ppt_to_S)
1282 endif
1283
1284 ! restoring boundary fluxes
12850 if (CS%restorebuoy) then
12860 if (CS%use_temperature) then
12870 do j=js,je ; do i=is,ie
12880 if (G%mask2dT(i,j) > 0.0) then
1289 fluxes%heat_added(i,j) = G%mask2dT(i,j) * &
12900 ((CS%T_Restore(i,j) - sfc_state%SST(i,j)) * rhoXcp * CS%Flux_const_T)
1291 fluxes%vprec(i,j) = - (CS%rho_restore*CS%Flux_const_S) * &
1292 (CS%S_Restore(i,j) - sfc_state%SSS(i,j)) / &
12930 (0.5*(sfc_state%SSS(i,j) + CS%S_Restore(i,j)))
1294 else
12950 fluxes%heat_added(i,j) = 0.0
12960 fluxes%vprec(i,j) = 0.0
1297 endif
1298 enddo ; enddo
1299 else
13000 do j=js,je ; do i=is,ie
13010 if (G%mask2dT(i,j) > 0.0) then
1302 fluxes%buoy(i,j) = (CS%Dens_Restore(i,j) - sfc_state%sfc_density(i,j)) * &
13030 (CS%G_Earth * CS%Flux_const / CS%rho_restore)
1304 else
13050 fluxes%buoy(i,j) = 0.0
1306 endif
1307 enddo ; enddo
1308 endif
1309 else ! not RESTOREBUOY
13100 if (.not.CS%use_temperature) then
1311 call MOM_error(FATAL, "buoyancy_forcing in MOM_surface_forcing: "// &
13120 "The fluxes need to be defined without RESTOREBUOY.")
1313 endif
1314 endif ! end RESTOREBUOY
1315
1316
1317 ! mask out land points and compute heat content of water fluxes
1318 ! assume liquid precip enters ocean at SST
1319 ! assume frozen precip enters ocean at 0degC
1320 ! assume liquid runoff enters ocean at SST
1321 ! assume solid runoff (calving) enters ocean at 0degC
1322 ! mass leaving ocean has heat_content determined in MOM_diabatic_driver.F90
13230 do j=js,je ; do i=is,ie
13240 fluxes%evap(i,j) = fluxes%evap(i,j) * G%mask2dT(i,j)
13250 fluxes%lprec(i,j) = fluxes%lprec(i,j) * G%mask2dT(i,j)
13260 fluxes%fprec(i,j) = fluxes%fprec(i,j) * G%mask2dT(i,j)
13270 fluxes%lrunoff(i,j) = fluxes%lrunoff(i,j) * G%mask2dT(i,j)
13280 fluxes%frunoff(i,j) = fluxes%frunoff(i,j) * G%mask2dT(i,j)
13290 fluxes%lw(i,j) = fluxes%lw(i,j) * G%mask2dT(i,j)
13300 fluxes%latent(i,j) = fluxes%latent(i,j) * G%mask2dT(i,j)
13310 fluxes%sens(i,j) = fluxes%sens(i,j) * G%mask2dT(i,j)
13320 fluxes%sw(i,j) = fluxes%sw(i,j) * G%mask2dT(i,j)
1333
13340 fluxes%latent_evap_diag(i,j) = fluxes%latent_evap_diag(i,j) * G%mask2dT(i,j)
13350 fluxes%latent_fprec_diag(i,j) = -fluxes%fprec(i,j)*CS%latent_heat_fusion
13360 fluxes%latent_frunoff_diag(i,j) = -fluxes%frunoff(i,j)*CS%latent_heat_fusion
1337 enddo ; enddo
1338
1339!#CTRL# if (associated(CS%ctrl_forcing_CSp)) then
1340!#CTRL# do j=js,je ; do i=is,ie
1341!#CTRL# SST_anom(i,j) = sfc_state%SST(i,j) - CS%T_Restore(i,j)
1342!#CTRL# SSS_anom(i,j) = sfc_state%SSS(i,j) - CS%S_Restore(i,j)
1343!#CTRL# SSS_mean(i,j) = 0.5*(sfc_state%SSS(i,j) + CS%S_Restore(i,j))
1344!#CTRL# enddo ; enddo
1345!#CTRL# call apply_ctrl_forcing(SST_anom, SSS_anom, SSS_mean, fluxes%heat_added, &
1346!#CTRL# fluxes%vprec, day, dt, G, US, CS%ctrl_forcing_CSp)
1347!#CTRL# endif
1348
13490 call callTree_leave("buoyancy_forcing_from_data_override")
13500end subroutine buoyancy_forcing_from_data_override
1351
1352!> This subroutine specifies zero surface buoyancy fluxes
13530subroutine buoyancy_forcing_zero(sfc_state, fluxes, day, dt, G, CS)
1354 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
1355 !! describe the surface state of the ocean.
1356 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
1357 type(time_type), intent(in) :: day !< The time of the fluxes
1358 real, intent(in) :: dt !< The amount of time over which
1359 !! the fluxes apply [T ~> s]
1360 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1361 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
1362 !! a previous surface_forcing_init call
1363 ! Local variables
1364 integer :: i, j, is, ie, js, je
1365
13660 call callTree_enter("buoyancy_forcing_zero, MOM_surface_forcing.F90")
13670 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
1368
13690 if (CS%use_temperature) then
13700 do j=js,je ; do i=is,ie
13710 fluxes%evap(i,j) = 0.0
13720 fluxes%lprec(i,j) = 0.0
13730 fluxes%fprec(i,j) = 0.0
13740 fluxes%vprec(i,j) = 0.0
13750 fluxes%lrunoff(i,j) = 0.0
13760 fluxes%frunoff(i,j) = 0.0
13770 fluxes%lw(i,j) = 0.0
13780 fluxes%latent(i,j) = 0.0
13790 fluxes%sens(i,j) = 0.0
13800 fluxes%sw(i,j) = 0.0
13810 fluxes%latent_evap_diag(i,j) = 0.0
13820 fluxes%latent_fprec_diag(i,j) = 0.0
13830 fluxes%latent_frunoff_diag(i,j) = 0.0
1384 enddo ; enddo
1385 else
13860 do j=js,je ; do i=is,ie
13870 fluxes%buoy(i,j) = 0.0
1388 enddo ; enddo
1389 endif
1390
13910 call callTree_leave("buoyancy_forcing_zero")
13920end subroutine buoyancy_forcing_zero
1393
1394
1395!> Sets up spatially and temporally constant surface heat fluxes.
13960subroutine buoyancy_forcing_const(sfc_state, fluxes, day, dt, G, US, CS)
1397 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
1398 !! describe the surface state of the ocean.
1399 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
1400 type(time_type), intent(in) :: day !< The time of the fluxes
1401 real, intent(in) :: dt !< The amount of time over which
1402 !! the fluxes apply [T ~> s]
1403 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1404 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1405 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
1406 !! a previous surface_forcing_init call
1407 ! Local variables
1408 integer :: i, j, is, ie, js, je
14090 call callTree_enter("buoyancy_forcing_const, MOM_surface_forcing.F90")
14100 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
1411
14120 if (CS%use_temperature) then
14130 do j=js,je ; do i=is,ie
14140 fluxes%evap(i,j) = 0.0
14150 fluxes%lprec(i,j) = 0.0
14160 fluxes%fprec(i,j) = 0.0
14170 fluxes%vprec(i,j) = 0.0
14180 fluxes%lrunoff(i,j) = 0.0
14190 fluxes%frunoff(i,j) = 0.0
14200 fluxes%lw(i,j) = 0.0
14210 fluxes%latent(i,j) = 0.0
14220 fluxes%sens(i,j) = CS%constantHeatForcing * G%mask2dT(i,j)
14230 fluxes%sw(i,j) = 0.0
14240 fluxes%latent_evap_diag(i,j) = 0.0
14250 fluxes%latent_fprec_diag(i,j) = 0.0
14260 fluxes%latent_frunoff_diag(i,j) = 0.0
1427 enddo ; enddo
1428 else
14290 do j=js,je ; do i=is,ie
14300 fluxes%buoy(i,j) = 0.0
1431 enddo ; enddo
1432 endif
1433
14340 call callTree_leave("buoyancy_forcing_const")
14350end subroutine buoyancy_forcing_const
1436
1437!> Sets surface fluxes of heat and salinity by restoring to temperature and
1438!! salinity profiles that vary linearly with latitude.
143912subroutine buoyancy_forcing_linear(sfc_state, fluxes, day, dt, G, US, CS)
1440 type(surface), intent(inout) :: sfc_state !< A structure containing fields that
1441 !! describe the surface state of the ocean.
1442 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
1443 type(time_type), intent(in) :: day !< The time of the fluxes
1444 real, intent(in) :: dt !< The amount of time over which
1445 !! the fluxes apply [T ~> s]
1446 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1447 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1448 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
1449 !! a previous surface_forcing_init call
1450 ! Local variables
1451 real :: y ! The latitude relative to the south normalized by the domain extent [nondim]
1452 real :: T_restore ! The temperature towards which to restore [C ~> degC]
1453 real :: S_restore ! The salinity towards which to restore [S ~> ppt]
1454 integer :: i, j, is, ie, js, je
1455
145612 call callTree_enter("buoyancy_forcing_linear, MOM_surface_forcing.F90")
145712 is = G%isc ; ie = G%iec ; js = G%jsc ; je = G%jec
1458
1459 ! This case has no surface buoyancy forcing.
146012 if (CS%use_temperature) then
146187132 do j=js,je ; do i=is,ie
146286400 fluxes%evap(i,j) = 0.0
146386400 fluxes%lprec(i,j) = 0.0
146486400 fluxes%fprec(i,j) = 0.0
146586400 fluxes%vprec(i,j) = 0.0
146686400 fluxes%lrunoff(i,j) = 0.0
146786400 fluxes%frunoff(i,j) = 0.0
146886400 fluxes%lw(i,j) = 0.0
146986400 fluxes%latent(i,j) = 0.0
147086400 fluxes%sens(i,j) = 0.0
147186400 fluxes%sw(i,j) = 0.0
147286400 fluxes%latent_evap_diag(i,j) = 0.0
147386400 fluxes%latent_fprec_diag(i,j) = 0.0
147487120 fluxes%latent_frunoff_diag(i,j) = 0.0
1475 enddo ; enddo
1476 else
14770 do j=js,je ; do i=is,ie
14780 fluxes%buoy(i,j) = 0.0
1479 enddo ; enddo
1480 endif
1481
148212 if (CS%restorebuoy) then
148312 if (CS%use_temperature) then
148487132 do j=js,je ; do i=is,ie
148586400 y = (G%geoLatCu(I,j)-CS%South_lat)/CS%len_lat
148686400 T_restore = CS%T_south + (CS%T_north-CS%T_south)*y
148786400 S_restore = CS%S_south + (CS%S_north-CS%S_south)*y
148887120 if (G%mask2dT(i,j) > 0.0) then
1489 fluxes%heat_added(i,j) = G%mask2dT(i,j) * &
149060168 ((T_Restore - sfc_state%SST(i,j)) * ((CS%rho_restore * fluxes%C_p) * CS%Flux_const))
1491 fluxes%vprec(i,j) = - (CS%rho_restore*CS%Flux_const) * &
1492 (S_Restore - sfc_state%SSS(i,j)) / &
149360168 (0.5*(sfc_state%SSS(i,j) + S_Restore))
1494 else
149526232 fluxes%heat_added(i,j) = 0.0
149626232 fluxes%vprec(i,j) = 0.0
1497 endif
1498 enddo ; enddo
1499 else
1500 call MOM_error(FATAL, "buoyancy_forcing_linear in MOM_surface_forcing: "// &
15010 "RESTOREBUOY to linear not written yet.")
1502 !do j=js,je ; do i=is,ie
1503 ! if (G%mask2dT(i,j) > 0.0) then
1504 ! fluxes%buoy(i,j) = (CS%Dens_Restore(i,j) - sfc_state%sfc_density(i,j)) * &
1505 ! (CS%G_Earth * CS%Flux_const / CS%rho_restore)
1506 ! else
1507 ! fluxes%buoy(i,j) = 0.0
1508 ! endif
1509 !enddo ; enddo
1510 endif
1511 else ! not RESTOREBUOY
15120 if (.not.CS%use_temperature) then
1513 call MOM_error(FATAL, "buoyancy_forcing_linear in MOM_surface_forcing: "// &
15140 "The fluxes need to be defined without RESTOREBUOY.")
1515 endif
1516 endif ! end RESTOREBUOY
1517
151812 call callTree_leave("buoyancy_forcing_linear")
151912end subroutine buoyancy_forcing_linear
1520
1521!> Return a time record to read from a file based on the model time, the number of time records in
1522!! that file and the number of time records per model day.
15230function get_file_time_level(Time, nlev_file, days_per_rec) result (time_lev)
1524 type(time_type), intent(in) :: Time !< The time of the fluxes
1525 integer , intent(in) :: nlev_file !< The number of time records in a forcing file
1526 integer , intent(in) :: days_per_rec !< If positive, the number of days spanned by each
1527 !! time record in a file, if negative the number
1528 !! time records per day, or if 0 determine this
1529 !! by guessing based on the number of records in
1530 !! the file. If this is 31, the time levels will
1531 !! be based on the months of the calendar.
1532 !! Setting this larger than 1000000 will always
1533 !! cause the time level to be set to 1.
1534 integer :: time_lev !< The time level in a file that will be read.
1535
1536 ! Local variables
1537 integer :: days, seconds ! The number of days and seconds since the start of the calendar
1538 integer :: year, month, day, hour, minute, second ! The components of the model time
1539 integer :: recs_per_day ! The number of file time records per day
1540 integer :: recs ! The number of time levels into the file to read without
1541 ! taking the periodicity of the file into account.
1542
15430 if ( (days_per_rec >= 1000000) .or. &
1544 ( (days_per_rec == 0) .and. .not.((nlev_file == 12) .or. (nlev_file == 365)) ) ) then
1545 ! The second condition above is to recreate the existing behavior, but it should perhaps be
1546 ! phased out.
15470 time_lev = 1
15480 elseif ( (days_per_rec == 31) .or. ((days_per_rec == 0) .and. (nlev_file == 12)) ) then
15490 call get_date(Time, year, month, day, hour, minute, second)
15500 time_lev = month
1551 else
15520 call get_time(Time, seconds, days)
15530 if ( (days_per_rec == 0) .or. (abs(days_per_rec) == 1) ) then
15540 recs = days
15550 elseif (days_per_rec < 0) then
15560 recs_per_day = -days_per_rec
15570 recs = days * recs_per_day + ( (recs_per_day*set_time(seconds, 0)) / set_time(0, 1) )
1558 ! When integer rounding in the time-type arithmetic is considered, the line above is equivalent to:
1559 ! seconds_per_day = set_time(0, 1) / set_time(1, 0)
1560 ! recs = days * recs_per_day + floor(real(recs_per_day*seconds) / real(seconds_per_day))
1561 else
15620 recs = days / days_per_rec
1563 endif
15640 time_lev = recs - nlev_file*floor(real(recs) / real(nlev_file)) + 1
1565 endif
1566
15670end function get_file_time_level
1568
1569!> Sets the necessary MARBL forcings via the data override facility.
15700subroutine MARBL_forcing_from_data_override(fluxes, day, G, US, CS)
1571 type(forcing), intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
1572 type(time_type), intent(in) :: day !< The time of the fluxes
1573 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
1574 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1575 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
1576 !! a previous surface_forcing_init call
1577 ! Local variables
1578 real, pointer, dimension(:,:) :: atm_co2_prog =>NULL() !< Prognostic atmospheric CO2 concentration [ppm]
1579 real, pointer, dimension(:,:) :: atm_co2_diag =>NULL() !< Diagnostic atmospheric CO2 concentration [ppm]
1580 real, pointer, dimension(:,:) :: atm_fine_dust_flux =>NULL() !< Fine dust flux from atmosphere
1581 !! [R Z T-1 ~> kg m-2 s-1]
1582 real, pointer, dimension(:,:) :: atm_coarse_dust_flux =>NULL() !< Coarse dust flux from atmosphere
1583 !! [R Z T-1 ~> kg m-2 s-1]
1584 real, pointer, dimension(:,:) :: seaice_dust_flux =>NULL() !< Dust flux from seaice
1585 !! [R Z T-1 ~> kg m-2 s-1]
1586 real, pointer, dimension(:,:) :: atm_bc_flux =>NULL() !< Black carbon flux from atmosphere
1587 !! [R Z T-1 ~> kg m-2 s-1]
1588 real, pointer, dimension(:,:) :: seaice_bc_flux =>NULL() !< Black carbon flux from seaice
1589 !! [R Z T-1 ~> kg m-2 s-1]
1590 real, pointer, dimension(:,:) :: nhx_dep =>NULL() !< Nitrogen deposition
1591 !! [R Z T-1 ~> kg m-2 s-1]
1592 real, pointer, dimension(:,:) :: noy_dep =>NULL() !< Nitrogen deposition
1593 !! [R Z T-1 ~> kg m-2 s-1]
1594 integer :: isc, iec, jsc, jec
1595
1596 ! Necessary null pointers for arguments to convert_driver_fields_to_forcings()
1597 ! Since they are null, MARBL will not use multiple ice categories
1598 real, pointer, dimension(:,:) :: afracr =>NULL()
1599 real, pointer, dimension(:,:) :: swnet_afracr =>NULL()
1600 real, pointer, dimension(:,:,:) :: swpen_ifrac_n =>NULL()
1601 real, pointer, dimension(:,:,:) :: ifrac_n =>NULL()
1602
16030 call callTree_enter("MARBL_forcing_from_data_override, MOM_surface_forcing.F90")
1604
16050 if (.not.CS%dataOverrideIsInitialized) then
16060 call data_override_init(G%Domain)
16070 CS%dataOverrideIsInitialized = .True.
1608 endif
1609
1610 ! Allocate memory for pointers
16110 isc = G%isc ; iec = G%iec ; jsc = G%jsc ; jec = G%jec
1612 allocate ( atm_co2_prog (isc:iec,jsc:jec), &
1613 atm_co2_diag (isc:iec,jsc:jec), &
1614 atm_fine_dust_flux (isc:iec,jsc:jec), &
1615 atm_coarse_dust_flux (isc:iec,jsc:jec), &
1616 seaice_dust_flux (isc:iec,jsc:jec), &
1617 atm_bc_flux (isc:iec,jsc:jec), &
1618 seaice_bc_flux (isc:iec,jsc:jec), &
1619 nhx_dep (isc:iec,jsc:jec), &
1620 noy_dep (isc:iec,jsc:jec), &
16210 source=0.0)
1622
1623
1624 ! fluxes used directly as MARBL inputs
1625 ! (should be scaled)
16260 call data_override(G%Domain, 'ice_fraction', fluxes%ice_fraction, day)
16270 call data_override(G%Domain, 'u10_sqr', fluxes%u10_sqr, day, scale=US%m_s_to_L_T**2)
1628
1629 ! fluxes used to compute MARBL inputs
1630 ! These are kept in physical units, and will be scaled appropriately in
1631 ! convert_driver_fields_to_forcings()
16320 call data_override(G%Domain, 'atm_co2_prog', atm_co2_prog, day)
16330 call data_override(G%Domain, 'atm_co2_diag', atm_co2_diag, day)
16340 call data_override(G%Domain, 'atm_fine_dust_flux', atm_fine_dust_flux, day)
16350 call data_override(G%Domain, 'atm_coarse_dust_flux', atm_coarse_dust_flux, day)
16360 call data_override(G%Domain, 'atm_bc_flux', atm_bc_flux, day)
16370 call data_override(G%Domain, 'seaice_dust_flux', seaice_dust_flux, day)
16380 call data_override(G%Domain, 'seaice_bc_flux', seaice_bc_flux, day)
16390 call data_override(G%Domain, 'nhx_dep', nhx_dep, day)
16400 call data_override(G%Domain, 'noy_dep', noy_dep, day)
1641
1642 call convert_driver_fields_to_forcings(atm_fine_dust_flux, atm_coarse_dust_flux, &
1643 seaice_dust_flux, atm_bc_flux, seaice_bc_flux, &
1644 nhx_dep, noy_dep, atm_co2_prog, atm_co2_diag, &
1645 afracr, swnet_afracr, ifrac_n, swpen_ifrac_n, &
16460 day, G, US, 0, 0, fluxes, CS%marbl_forcing_CSp)
1647
16480 deallocate ( atm_co2_prog, &
16490 atm_co2_diag, &
16500 atm_fine_dust_flux, &
16510 atm_coarse_dust_flux, &
16520 seaice_dust_flux, &
16530 atm_bc_flux, &
16540 seaice_bc_flux, &
16550 nhx_dep, &
16560 noy_dep)
1657
16580 call callTree_leave("MARBL_forcing_from_data_override")
1659
16600end subroutine MARBL_forcing_from_data_override
1661
1662!> Save a restart file for the forcing fields
16630subroutine forcing_save_restart(CS, G, Time, directory, time_stamped, &
1664 filename_suffix)
1665 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
1666 !! a previous surface_forcing_init call
1667 type(ocean_grid_type), intent(inout) :: G !< The ocean's grid structure
1668 type(time_type), intent(in) :: Time !< model time at this call; needed for mpp_write calls
1669 character(len=*), intent(in) :: directory !< directory into which to write these restart files
1670 logical, optional, intent(in) :: time_stamped !< If true, the restart file names
1671 !! include a unique time stamp; the default is false.
1672 character(len=*), optional, intent(in) :: filename_suffix !< optional suffix (e.g., a time-stamp)
1673 !! to append to the restart file name
1674
16750 if (.not.associated(CS)) return
16760 if (.not.associated(CS%restart_CSp)) return
1677
16780 call save_restart(directory, Time, G, CS%restart_CSp, time_stamped)
1679
16800end subroutine forcing_save_restart
1681
1682!> Initialize the surface forcing module
16831subroutine surface_forcing_init(Time, G, US, param_file, diag, CS, tracer_flow_CSp)
1684 type(time_type), intent(in) :: Time !< The current model time
1685 type(ocean_grid_type), intent(in) :: G !< The ocean's grid structure
1686 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
1687 type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
1688 type(diag_ctrl), target, intent(inout) :: diag !< structure used to regulate diagnostic output
1689 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
1690 !! a previous surface_forcing_init call
1691 type(tracer_flow_control_CS), pointer :: tracer_flow_CSp !< Forcing for tracers?
1692
1693 ! Local variables
1694 type(directories) :: dirs
1695 logical :: new_sim
1696 type(time_type) :: Time_frc
1697 ! This include declares and sets the variable "version".
1698# include "version_variable.h"
1699 real :: flux_const_default ! The unscaled value of FLUXCONST [m day-1]
1700 logical :: Boussinesq ! If true, this run is fully Boussinesq
1701 logical :: semi_Boussinesq ! If true, this run is partially non-Boussinesq
1702 logical :: fix_ustar_gustless_bug ! If false, include a bug using an older run-time parameter.
1703 logical :: test_value ! This is used to determine whether a logical parameter is being set explicitly.
1704 logical :: explicit_bug, explicit_fix ! These indicate which parameters are set explicitly.
1705 integer :: default_answer_date ! The default setting for the various ANSWER_DATE flags.
1706 character(len=40) :: mdl = "MOM_surface_forcing" ! This module's name.
1707 character(len=200) :: filename, gust_file ! The name of the gustiness input file.
1708
17091 if (associated(CS)) then
1710 call MOM_error(WARNING, "surface_forcing_init called with an associated "// &
17110 "control structure.")
17120 return
1713 endif
171441 allocate(CS)
1715
17161 id_clock_forcing=cpu_clock_id('(Ocean surface forcing)', grain=CLOCK_MODULE)
17171 call cpu_clock_begin(id_clock_forcing)
1718
17191 CS%diag => diag
17201 if (associated(tracer_flow_CSp)) CS%tracer_flow_CSp => tracer_flow_CSp
1721
1722 ! Read all relevant parameters and write them to the model log.
17231 call log_version(param_file, mdl, version, '')
1724 call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", CS%use_temperature, &
1725 "If true, Temperature and salinity are used as state "//&
17261 "variables.", default=.true.)
1727 call get_param(param_file, "MOM", "BOUSSINESQ", Boussinesq, &
17281 "If true, make the Boussinesq approximation.", default=.true., do_not_log=.true.)
1729 call get_param(param_file, "MOM", "SEMI_BOUSSINESQ", semi_Boussinesq, &
1730 "If true, do non-Boussinesq pressure force calculations and use mass-based "//&
1731 "thicknesses, but use RHO_0 to convert layer thicknesses into certain "//&
1732 "height changes. This only applies if BOUSSINESQ is false.", &
17331 default=.true., do_not_log=.true.)
17341 CS%nonBous = .not.(Boussinesq .or. semi_Boussinesq)
1735 call get_param(param_file, mdl, "INPUTDIR", CS%inputdir, &
1736 "The directory in which all input files are found.", &
17371 default=".")
17381 CS%inputdir = slasher(CS%inputdir)
1739
1740 call get_param(param_file, mdl, "ADIABATIC", CS%adiabatic, &
1741 "There are no diapycnal mass fluxes if ADIABATIC is "//&
1742 "true. This assumes that KD = KDML = 0.0 and that "//&
1743 "there is no buoyancy forcing, but makes the model "//&
17441 "faster by eliminating subroutine calls.", default=.false.)
1745 call get_param(param_file, mdl, "VARIABLE_WINDS", CS%variable_winds, &
1746 "If true, the winds vary in time after the initialization.", &
17471 default=.true.)
1748 call get_param(param_file, mdl, "VARIABLE_BUOYFORCE", CS%variable_buoyforce, &
1749 "If true, the buoyancy forcing varies in time after the "//&
17501 "initialization of the model.", default=.true.)
1751
1752 ! Determine parameters related to the buoyancy forcing.
1753 call get_param(param_file, mdl, "BUOY_CONFIG", CS%buoy_config, &
1754 "The character string that indicates how buoyancy forcing is specified. Valid "//&
1755 "options include (file), (data_override), (zero), (const), (linear), (MESO), "//&
17561 "(SCM_CVmix_tests), (BFB), (dumbbell), (USER) and (NONE).", default="zero")
17571 if (trim(CS%buoy_config) == "file") then
1758 call get_param(param_file, mdl, "ARCHAIC_OMIP_FORCING_FILE", CS%archaic_OMIP_file, &
1759 "If true, use the forcing variable decomposition from "//&
1760 "the old German OMIP prescription that predated CORE. If "//&
1761 "false, use the variable groupings available from MOM "//&
17620 "output diagnostics of forcing variables.", default=.true.)
17630 if (CS%archaic_OMIP_file) then
1764 call get_param(param_file, mdl, "LONGWAVEDOWN_FILE", CS%longwave_file, &
1765 "The file with the downward longwave heat flux, in "//&
17660 "variable lwdn_sfc.", fail_if_missing=.true.)
1767 call get_param(param_file, mdl, "LONGWAVEUP_FILE", CS%longwaveup_file, &
1768 "The file with the upward longwave heat flux, in "//&
17690 "variable lwup_sfc.", fail_if_missing=.true.)
1770 call get_param(param_file, mdl, "EVAPORATION_FILE", CS%evaporation_file, &
1771 "The file with the evaporative moisture flux, in "//&
17720 "variable evap.", fail_if_missing=.true.)
1773 call get_param(param_file, mdl, "SENSIBLEHEAT_FILE", CS%sensibleheat_file, &
1774 "The file with the sensible heat flux, in "//&
17750 "variable shflx.", fail_if_missing=.true.)
1776 call get_param(param_file, mdl, "SHORTWAVEUP_FILE", CS%shortwaveup_file, &
1777 "The file with the upward shortwave heat flux.", &
17780 fail_if_missing=.true.)
1779 call get_param(param_file, mdl, "SHORTWAVEDOWN_FILE", CS%shortwave_file, &
1780 "The file with the downward shortwave heat flux.", &
17810 fail_if_missing=.true.)
1782 call get_param(param_file, mdl, "SNOW_FILE", CS%snow_file, &
1783 "The file with the downward frozen precip flux, in "//&
17840 "variable snow.", fail_if_missing=.true.)
1785 call get_param(param_file, mdl, "PRECIP_FILE", CS%rain_file, &
1786 "The file with the downward total precip flux, in "//&
17870 "variable precip.", fail_if_missing=.true.)
1788 call get_param(param_file, mdl, "FRESHDISCHARGE_FILE", CS%runoff_file, &
1789 "The file with the fresh and frozen runoff/calving fluxes, "//&
17900 "invariables disch_w and disch_s.", fail_if_missing=.true.)
1791
1792 ! These variable names are hard-coded, per the archaic OMIP conventions.
17930 CS%latentheat_file = CS%evaporation_file ; CS%latent_var = "evap"
17940 CS%LW_var = "lwdn_sfc" ; CS%SW_var = "swdn_sfc" ; CS%sens_var = "shflx"
17950 CS%evap_var = "evap" ; CS%rain_var = "precip" ; CS%snow_var = "snow"
17960 CS%lrunoff_var = "disch_w" ; CS%frunoff_var = "disch_s"
1797
1798 else
1799 call get_param(param_file, mdl, "LONGWAVE_FILE", CS%longwave_file, &
1800 "The file with the longwave heat flux, in the variable "//&
18010 "given by LONGWAVE_FORCING_VAR.", fail_if_missing=.true.)
1802 call get_param(param_file, mdl, "LONGWAVE_FORCING_VAR", CS%LW_var, &
18030 "The variable with the longwave forcing field.", default="LW")
1804 call get_param(param_file, mdl, "LONGWAVE_FILE_DAYS_PER_RECORD", CS%LW_days_per_rec, &
1805 "If positive the number of days of longwave fluxes per time level in LONGWAVE_FILE, "//&
1806 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1807 "or if 0 the model will guess the right value based on the file size.", &
18080 default=0)
1809
1810 call get_param(param_file, mdl, "SHORTWAVE_FILE", CS%shortwave_file, &
1811 "The file with the shortwave heat flux, in the variable "//&
18120 "given by SHORTWAVE_FORCING_VAR.", fail_if_missing=.true.)
1813 call get_param(param_file, mdl, "SHORTWAVE_FORCING_VAR", CS%SW_var, &
18140 "The variable with the shortwave forcing field.", default="SW")
1815 call get_param(param_file, mdl, "SHORTWAVE_FILE_DAYS_PER_RECORD", CS%SW_days_per_rec, &
1816 "If positive the number of days of shortwave fluxes per time level in SHORTWAVE_FILE, "//&
1817 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1818 "or if 0 the model will guess the right value based on the file size.", &
18190 default=CS%LW_days_per_rec)
1820
1821 call get_param(param_file, mdl, "EVAPORATION_FILE", CS%evaporation_file, &
1822 "The file with the evaporative moisture flux, in the "//&
18230 "variable given by EVAP_FORCING_VAR.", fail_if_missing=.true.)
1824 call get_param(param_file, mdl, "EVAP_FORCING_VAR", CS%evap_var, &
1825 "The variable with the evaporative moisture flux.", &
18260 default="evap")
1827 call get_param(param_file, mdl, "EVAPORATION_FILE_DAYS_PER_RECORD", CS%evap_days_per_rec, &
1828 "If positive the number of days of evaporation per time level in EVAPORATION_FILE, "//&
1829 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1830 "or if 0 the model will guess the right value based on the file size.", &
18310 default=CS%LW_days_per_rec)
1832
1833 call get_param(param_file, mdl, "LATENTHEAT_FILE", CS%latentheat_file, &
1834 "The file with the latent heat flux, in the variable "//&
18350 "given by LATENT_FORCING_VAR.", fail_if_missing=.true.)
1836 call get_param(param_file, mdl, "LATENT_FORCING_VAR", CS%latent_var, &
18370 "The variable with the latent heat flux.", default="latent")
1838 call get_param(param_file, mdl, "LATENTHEAT_FILE_DAYS_PER_RECORD", CS%latent_days_per_rec, &
1839 "If positive the number of days of latent heat fluxes per time level in LATENTHEAT_FILE, "//&
1840 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1841 "or if 0 the model will guess the right value based on the file size.", &
18420 default=CS%LW_days_per_rec)
1843
1844 call get_param(param_file, mdl, "SENSIBLEHEAT_FILE", CS%sensibleheat_file, &
1845 "The file with the sensible heat flux, in the variable "//&
18460 "given by SENSIBLE_FORCING_VAR.", fail_if_missing=.true.)
1847 call get_param(param_file, mdl, "SENSIBLE_FORCING_VAR", CS%sens_var, &
18480 "The variable with the sensible heat flux.", default="sensible")
1849 call get_param(param_file, mdl, "SENSIBLEHEAT_FILE_DAYS_PER_RECORD", CS%sens_days_per_rec, &
1850 "If positive the number of days of sensible heat fluxes per time level in SENSIBLEHEAT_FILE, "//&
1851 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1852 "or if 0 the model will guess the right value based on the file size.", &
18530 default=CS%LW_days_per_rec)
1854
1855 call get_param(param_file, mdl, "RAIN_FILE", CS%rain_file, &
1856 "The file with the liquid precipitation flux, in the "//&
18570 "variable given by RAIN_FORCING_VAR.", fail_if_missing=.true.)
1858 call get_param(param_file, mdl, "RAIN_FORCING_VAR", CS%rain_var, &
1859 "The variable with the liquid precipitation flux.", &
18600 default="liq_precip")
1861 call get_param(param_file, mdl, "RAIN_FILE_DAYS_PER_RECORD", CS%precip_days_per_rec, &
1862 "If positive the number of days of rain fluxes per time level in RAIN_FILE, "//&
1863 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1864 "or if 0 the model will guess the right value based on the file size.", &
18650 default=CS%LW_days_per_rec)
1866 call get_param(param_file, mdl, "SNOW_FILE", CS%snow_file, &
1867 "The file with the frozen precipitation flux, in the "//&
18680 "variable given by SNOW_FORCING_VAR.", fail_if_missing=.true.)
1869 call get_param(param_file, mdl, "SNOW_FORCING_VAR", CS%snow_var, &
1870 "The variable with the frozen precipitation flux.", &
18710 default="froz_precip")
1872 call get_param(param_file, mdl, "SHORTWAVE_FILE_DAYS_PER_RECORD", CS%SW_days_per_rec, &
1873 "If positive the number of days of shortwave fluxes per time level in SHORTWAVE_FILE, "//&
1874 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1875 "or if 0 the model will guess the right value based on the file size.", &
18760 default=CS%LW_days_per_rec)
1877
1878 call get_param(param_file, mdl, "RUNOFF_FILE", CS%runoff_file, &
1879 "The file with the fresh and frozen runoff/calving "//&
1880 "fluxes, in variables given by LIQ_RUNOFF_FORCING_VAR "//&
18810 "and FROZ_RUNOFF_FORCING_VAR.", fail_if_missing=.true.)
1882 call get_param(param_file, mdl, "LIQ_RUNOFF_FORCING_VAR", CS%lrunoff_var, &
1883 "The variable with the liquid runoff flux.", &
18840 default="liq_runoff")
1885 call get_param(param_file, mdl, "FROZ_RUNOFF_FORCING_VAR", CS%frunoff_var, &
1886 "The variable with the frozen runoff flux.", &
18870 default="froz_runoff")
1888 call get_param(param_file, mdl, "RUNOFF_FILE_DAYS_PER_RECORD", CS%SW_days_per_rec, &
1889 "If positive the number of days of runoff per time level in RUNOFF_FILE, "//&
1890 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1891 "or if 0 the model will guess the right value based on the file size.", &
18920 default=0)
1893 endif
1894
1895 call get_param(param_file, mdl, "SSTRESTORE_FILE", CS%SSTrestore_file, &
1896 "The file with the SST toward which to restore in the "//&
18970 "variable given by SST_RESTORE_VAR.", fail_if_missing=.true.)
1898 call get_param(param_file, mdl, "SALINITYRESTORE_FILE", CS%salinityrestore_file, &
1899 "The file with the surface salinity toward which to "//&
1900 "restore in the variable given by SSS_RESTORE_VAR.", &
19010 fail_if_missing=.true.)
19020 if (CS%archaic_OMIP_file) then
19030 CS%SST_restore_var = "TEMP" ; CS%SSS_restore_var = "SALT"
1904 else
1905 call get_param(param_file, mdl, "SST_RESTORE_VAR", CS%SST_restore_var, &
1906 "The variable with the SST toward which to restore.", &
19070 default="SST")
1908 call get_param(param_file, mdl, "SSTRESTORE_FILE_DAYS_PER_RECORD", CS%SST_days_per_rec, &
1909 "If positive the number of days of SST per time level in SSTRESTORE_FILE, "//&
1910 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1911 "or if 0 the model will guess the right value based on the file size.", &
19120 default=0)
1913 call get_param(param_file, mdl, "SSS_RESTORE_VAR", CS%SSS_restore_var, &
1914 "The variable with the SSS toward which to restore.", &
19150 default="SSS")
1916 call get_param(param_file, mdl, "SALINITYRESTORE_FILE_DAYS_PER_RECORD", CS%SSS_days_per_rec, &
1917 "If positive the number of days of salinity per time level in SALINITYRESTORE_FILE, "//&
1918 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1919 "or if 0 the model will guess the right value based on the file size.", &
19200 default=CS%SST_days_per_rec)
1921 endif
1922
1923 ! Add inputdir to the file names.
19240 CS%shortwave_file = trim(CS%inputdir)//trim(CS%shortwave_file)
19250 CS%longwave_file = trim(CS%inputdir)//trim(CS%longwave_file)
19260 CS%sensibleheat_file = trim(CS%inputdir)//trim(CS%sensibleheat_file)
19270 CS%latentheat_file = trim(CS%inputdir)//trim(CS%latentheat_file)
19280 CS%evaporation_file = trim(CS%inputdir)//trim(CS%evaporation_file)
19290 CS%snow_file = trim(CS%inputdir)//trim(CS%snow_file)
19300 CS%rain_file = trim(CS%inputdir)//trim(CS%rain_file)
19310 CS%runoff_file = trim(CS%inputdir)//trim(CS%runoff_file)
1932
19330 CS%shortwaveup_file = trim(CS%inputdir)//trim(CS%shortwaveup_file)
19340 CS%longwaveup_file = trim(CS%inputdir)//trim(CS%longwaveup_file)
1935
19360 CS%SSTrestore_file = trim(CS%inputdir)//trim(CS%SSTrestore_file)
19370 CS%salinityrestore_file = trim(CS%inputdir)//trim(CS%salinityrestore_file)
19381 elseif (trim(CS%buoy_config) == "const") then
1939 call get_param(param_file, mdl, "SENSIBLE_HEAT_FLUX", CS%constantHeatForcing, &
1940 "A constant heat forcing (positive into ocean) applied "//&
1941 "through the sensible heat flux field. ", &
19420 units='W/m2', scale=US%W_m2_to_QRZ_T, fail_if_missing=.true.)
1943 endif
1944
1945 ! Determine parameters related to the wind forcing.
1946 call get_param(param_file, mdl, "WIND_CONFIG", CS%wind_config, &
1947 "The character string that indicates how wind forcing is specified. Valid "//&
1948 "options include (file), (data_override), (2gyre), (1gyre), (gyres), (zero), "//&
1949 "(const), (Neverworld), (scurves), (ideal_hurr), (SCM_CVmix_tests) and (USER).", &
19501 default="zero")
19511 if (trim(CS%wind_config) == "file") then
1952 call get_param(param_file, mdl, "WIND_FILE", CS%wind_file, &
1953 "The file in which the wind stresses are found in "//&
19540 "variables STRESS_X and STRESS_Y.", fail_if_missing=.true.)
1955 call get_param(param_file, mdl, "WINDSTRESS_X_VAR",CS%stress_x_var, &
1956 "The name of the x-wind stress variable in WIND_FILE.", &
19570 default="STRESS_X")
1958 call get_param(param_file, mdl, "WINDSTRESS_Y_VAR", CS%stress_y_var, &
1959 "The name of the y-wind stress variable in WIND_FILE.", &
19600 default="STRESS_Y")
1961 call get_param(param_file, mdl, "WIND_STAGGER",CS%wind_stagger, &
1962 "A character indicating how the wind stress components "//&
1963 "are staggered in WIND_FILE. This may be A or C for now.", &
19640 default="C")
1965 call get_param(param_file, mdl, "WINDSTRESS_SCALE", CS%wind_scale, &
1966 "A value by which the wind stresses in WIND_FILE are rescaled.", &
19670 default=1.0, units="nondim")
1968 call get_param(param_file, mdl, "USTAR_FORCING_VAR", CS%ustar_var, &
1969 "The name of the friction velocity variable in WIND_FILE "//&
1970 "or blank to get ustar from the wind stresses plus the "//&
19710 "gustiness.", default=" ")
19720 CS%wind_file = trim(CS%inputdir) // trim(CS%wind_file)
1973 call get_param(param_file, mdl, "WIND_FILE_DAYS_PER_RECORD", CS%wind_days_per_rec, &
1974 "If positive the number of days of wind stress per time level in WIND_FILE, "//&
1975 "or if negative the number of time levels per day. If 31 change forcing monthly, "//&
1976 "or if 0 the model will guess the right value based on the file size.", &
19770 default=0)
1978 endif
19791 if (trim(CS%wind_config) == "gyres") then
1980 call get_param(param_file, mdl, "TAUX_CONST", CS%gyres_taux_const, &
1981 "With the gyres wind_config, the constant offset in the "//&
1982 "zonal wind stress profile: "//&
1983 " A in taux = A + B*sin(n*pi*y/L) + C*cos(n*pi*y/L).", &
19841 units="Pa", default=0.0, scale=US%Pa_to_RLZ_T2)
1985 call get_param(param_file, mdl, "TAUX_SIN_AMP", CS%gyres_taux_sin_amp, &
1986 "With the gyres wind_config, the sine amplitude in the "//&
1987 "zonal wind stress profile: "//&
1988 " B in taux = A + B*sin(n*pi*y/L) + C*cos(n*pi*y/L).", &
19891 units="Pa", default=0.0, scale=US%Pa_to_RLZ_T2)
1990 call get_param(param_file, mdl, "TAUX_COS_AMP", CS%gyres_taux_cos_amp, &
1991 "With the gyres wind_config, the cosine amplitude in "//&
1992 "the zonal wind stress profile: "//&
1993 " C in taux = A + B*sin(n*pi*y/L) + C*cos(n*pi*y/L).", &
19941 units="Pa", default=0.0, scale=US%Pa_to_RLZ_T2)
1995 call get_param(param_file, mdl, "TAUX_N_PIS",CS%gyres_taux_n_pis, &
1996 "With the gyres wind_config, the number of gyres in "//&
1997 "the zonal wind stress profile: "//&
1998 " n in taux = A + B*sin(n*pi*y/L) + C*cos(n*pi*y/L).", &
19991 units="nondim", default=0.0)
2000 call get_param(param_file, mdl, "DEFAULT_ANSWER_DATE", default_answer_date, &
2001 "This sets the default value for the various _ANSWER_DATE parameters.", &
20021 default=99991231)
2003 call get_param(param_file, mdl, "WIND_GYRES_ANSWER_DATE", CS%answer_date, &
2004 "The vintage of the expressions used to set gyre wind stresses. "//&
2005 "Values below 20190101 recover the answers from the end of 2018, "//&
2006 "while higher values use a form of the gyre wind stresses that are "//&
2007 "rotationally invariant and more likely to be the same between compilers.", &
20081 default=default_answer_date)
2009 else
20100 CS%answer_date = 20190101
2011 endif
20121 if (trim(CS%wind_config) == "scurves") then
2013 call get_param(param_file, mdl, "WIND_SCURVES_LATS", CS%scurves_ydata, &
2014 "A list of latitudes defining a piecewise scurve profile "//&
2015 "for zonal wind stress.", &
20160 units="degrees N", fail_if_missing=.true.)
2017 call get_param(param_file, mdl, "WIND_SCURVES_TAUX", CS%scurves_taux, &
2018 "A list of zonal wind stress values at latitudes "//&
2019 "WIND_SCURVES_LATS defining a piecewise scurve profile.", &
20200 units="Pa", scale=US%Pa_to_RLZ_T2, fail_if_missing=.true.)
2021 endif
20221 if (trim(CS%wind_config) == "2gyre") then
2023 call get_param(param_file, mdl, "TAUX_MAGNITUDE", CS%taux_mag, &
2024 "The peak zonal wind stress when WIND_CONFIG = 2gyre.", &
20250 units="Pa", default=0.1, scale=US%Pa_to_RLZ_T2)
2026 endif
20271 if (trim(CS%wind_config) == "1gyre") then
2028 call get_param(param_file, mdl, "TAUX_MAGNITUDE", CS%taux_mag, &
2029 "The peak zonal wind stress when WIND_CONFIG = 1gyre.", &
20300 units="Pa", default=-0.2, scale=US%Pa_to_RLZ_T2)
2031 endif
20321 if (trim(CS%wind_config) == "Neverworld" .or. trim(CS%wind_config) == "Neverland") then
2033 call get_param(param_file, mdl, "TAUX_MAGNITUDE", CS%taux_mag, &
2034 "The peak zonal wind stress when WIND_CONFIG = Neverworld.", &
20350 units="Pa", default=0.2, scale=US%Pa_to_RLZ_T2)
2036 endif
2037
2038 if ((trim(CS%wind_config) == "2gyre") .or. &
2039 (trim(CS%wind_config) == "1gyre") .or. &
20401 (trim(CS%wind_config) == "gyres") .or. &
2041 (trim(CS%buoy_config) == "linear")) then
20421 CS%south_lat = G%south_lat
20431 CS%len_lat = G%len_lat
2044 endif
2045
2046 call get_param(param_file, mdl, "RHO_0", CS%Rho0, &
2047 "The mean ocean density used with BOUSSINESQ true to "//&
2048 "calculate accelerations and the mass for conservation "//&
2049 "properties, or with BOUSSINESQ false to convert some "//&
2050 "parameters from vertical units of m to kg m-2.", &
20511 units="kg m-3", default=1035.0, scale=US%kg_m3_to_R) ! (, do_not_log=CS%nonBous)
2052 call get_param(param_file, mdl, "RESTOREBUOY", CS%restorebuoy, &
2053 "If true, the buoyancy fluxes drive the model back toward some "//&
20541 "specified surface state with a rate given by FLUXCONST.", default=.false.)
2055 call get_param(param_file, mdl, "LATENT_HEAT_FUSION", CS%latent_heat_fusion, &
2056 "The latent heat of fusion.", default=hlf, &
20571 units="J/kg", scale=US%J_kg_to_Q)
2058 call get_param(param_file, mdl, "LATENT_HEAT_VAPORIZATION", CS%latent_heat_vapor, &
20591 "The latent heat of fusion.", default=hlv, units="J/kg", scale=US%J_kg_to_Q)
20601 if (CS%restorebuoy) then
2061 ! These three variables use non-standard time units, but are rescaled as they are read.
2062 call get_param(param_file, mdl, "FLUXCONST", CS%Flux_const, &
2063 "The constant that relates the restoring surface fluxes to the relative "//&
2064 "surface anomalies (akin to a piston velocity). Note the non-MKS units.", &
20651 default=0.0, units="m day-1", scale=US%m_to_Z*US%T_to_s/86400.0)
2066
20671 if (CS%use_temperature) then
2068 call get_param(param_file, mdl, "FLUXCONST", flux_const_default, &
20691 default=0.0, units="m day-1", do_not_log=.true.)
2070 call get_param(param_file, mdl, "FLUXCONST_T", CS%Flux_const_T, &
2071 "The constant that relates the restoring surface temperature flux to the "//&
2072 "relative surface anomaly (akin to a piston velocity). Note the non-MKS units.", &
20731 units="m day-1", scale=US%m_to_Z*US%T_to_s/86400.0, default=flux_const_default)
2074 call get_param(param_file, mdl, "FLUXCONST_S", CS%Flux_const_S, &
2075 "The constant that relates the restoring surface salinity flux to the "//&
2076 "relative surface anomaly (akin to a piston velocity). Note the non-MKS units.", &
20771 units="m day-1", scale=US%m_to_Z*US%T_to_s/86400.0, default=flux_const_default)
2078 endif
2079
20801 if (trim(CS%buoy_config) == "linear") then
2081 call get_param(param_file, mdl, "SST_NORTH", CS%T_north, &
2082 "With buoy_config linear, the sea surface temperature "//&
2083 "at the northern end of the domain toward which to "//&
20841 "to restore.", units="degC", default=0.0, scale=US%degC_to_C)
2085 call get_param(param_file, mdl, "SST_SOUTH", CS%T_south, &
2086 "With buoy_config linear, the sea surface temperature "//&
2087 "at the southern end of the domain toward which to "//&
20881 "to restore.", units="degC", default=0.0, scale=US%degC_to_C)
2089 call get_param(param_file, mdl, "SSS_NORTH", CS%S_north, &
2090 "With buoy_config linear, the sea surface salinity "//&
2091 "at the northern end of the domain toward which to "//&
20921 "to restore.", units="ppt", default=35.0, scale=US%ppt_to_S)
2093 call get_param(param_file, mdl, "SSS_SOUTH", CS%S_south, &
2094 "With buoy_config linear, the sea surface salinity "//&
2095 "at the southern end of the domain toward which to "//&
20961 "to restore.", units="ppt", default=35.0, scale=US%ppt_to_S)
2097 endif
2098 call get_param(param_file, mdl, "RESTORE_FLUX_RHO", CS%rho_restore, &
2099 "The density that is used to convert piston velocities into salt or heat "//&
2100 "fluxes with RESTORE_SALINITY or RESTORE_TEMPERATURE.", &
2101 units="kg m-3", default=CS%Rho0*US%R_to_kg_m3, scale=US%kg_m3_to_R, &
2102 do_not_log=(((CS%Flux_const==0.0).and.(CS%Flux_const_T==0.0).and.(CS%Flux_const_S==0.0))&
21031 .or.(.not.CS%restorebuoy)))
2104 endif
2105 call get_param(param_file, mdl, "G_EARTH", CS%G_Earth, &
2106 "The gravitational acceleration of the Earth.", &
21071 units="m s-2", default=9.80, scale=US%m_to_L**2*US%Z_to_m*US%T_to_s**2)
2108
2109 call get_param(param_file, mdl, "GUST_CONST", CS%gust_const, &
2110 "The background gustiness in the winds.", &
21111 units="Pa", default=0.0, scale=US%Pa_to_RLZ_T2*US%L_to_Z)
2112
2113 call get_param(param_file, mdl, "USTAR_GUSTLESS_BUG", CS%ustar_gustless_bug, &
2114 "If true include a bug in the time-averaging of the gustless wind friction velocity", &
21151 default=.false., do_not_log=.true.)
2116 ! This is used to test whether USTAR_GUSTLESS_BUG is being actively set.
21171 call get_param(param_file, mdl, "USTAR_GUSTLESS_BUG", test_value, default=.true., do_not_log=.true.)
21181 explicit_bug = CS%ustar_gustless_bug .eqv. test_value
2119 call get_param(param_file, mdl, "FIX_USTAR_GUSTLESS_BUG", fix_ustar_gustless_bug, &
2120 "If true correct a bug in the time-averaging of the gustless wind friction velocity", &
21211 default=.true., do_not_log=.true.)
21221 call get_param(param_file, mdl, "FIX_USTAR_GUSTLESS_BUG", test_value, default=.false., do_not_log=.true.)
21231 explicit_fix = fix_ustar_gustless_bug .eqv. test_value
2124
21251 if (explicit_bug .and. explicit_fix .and. (fix_ustar_gustless_bug .eqv. CS%ustar_gustless_bug)) then
2126 ! USTAR_GUSTLESS_BUG is being explicitly set, and should not be changed.
2127 call MOM_error(FATAL, "USTAR_GUSTLESS_BUG and FIX_USTAR_GUSTLESS_BUG are both being set "//&
2128 "with inconsistent values. FIX_USTAR_GUSTLESS_BUG is an obsolete "//&
21290 "parameter and should be removed.")
21301 elseif (explicit_fix) then
2131 call MOM_error(WARNING, "FIX_USTAR_GUSTLESS_BUG is an obsolete parameter. "//&
21320 "Use USTAR_GUSTLESS_BUG instead (noting that it has the opposite sense).")
21330 CS%ustar_gustless_bug = .not.fix_ustar_gustless_bug
2134 endif
2135 call log_param(param_file, mdl, "USTAR_GUSTLESS_BUG", CS%ustar_gustless_bug, &
2136 "If true include a bug in the time-averaging of the gustless wind friction velocity", &
21371 default=.false.)
2138
2139 call get_param(param_file, mdl, "READ_GUST_2D", CS%read_gust_2d, &
2140 "If true, use a 2-dimensional gustiness supplied from "//&
21411 "an input file", default=.false.)
21421 if (CS%read_gust_2d) then
2143 call get_param(param_file, mdl, "GUST_2D_FILE", gust_file, &
2144 "The file in which the wind gustiness is found in "//&
21450 "variable gustiness.", fail_if_missing=.true.)
21460 call safe_alloc_ptr(CS%gust,G%isd,G%ied,G%jsd,G%jed)
21470 filename = trim(CS%inputdir) // trim(gust_file)
2148 ! NOTE: There are certain cases where FMS is unable to read this file, so
2149 ! we use read_netCDF_data in place of MOM_read_data.
2150 call read_netCDF_data(filename, 'gustiness', CS%gust, G%Domain, &
21510 rescale=US%Pa_to_RLZ_T2*US%L_to_Z) ! units in file should be [Pa]
2152 endif
2153 call get_param(param_file, mdl, "USE_MARBL_TRACERS", CS%use_marbl_tracers, &
21541 default=.false., do_not_log=.true.)
2155
2156! All parameter settings are now known.
2157
21581 if (trim(CS%wind_config) == "USER" .or. trim(CS%buoy_config) == "USER" ) then
21590 call USER_surface_forcing_init(Time, G, US, param_file, diag, CS%user_forcing_CSp)
21601 elseif (trim(CS%buoy_config) == "BFB" ) then
21610 call BFB_surface_forcing_init(Time, G, US, param_file, diag, CS%BFB_forcing_CSp)
21621 elseif (trim(CS%buoy_config) == "dumbbell" ) then
21630 call dumbbell_surface_forcing_init(Time, G, US, param_file, diag, CS%dumbbell_forcing_CSp)
21641 elseif (trim(CS%wind_config) == "MESO" .or. trim(CS%buoy_config) == "MESO" ) then
21650 call MESO_surface_forcing_init(Time, G, US, param_file, diag, CS%MESO_forcing_CSp)
21661 elseif (trim(CS%wind_config) == "ideal_hurr") then
21670 call idealized_hurricane_wind_init(Time, G, US, param_file, CS%idealized_hurricane_CSp)
21681 elseif (trim(CS%wind_config) == "SCM_ideal_hurr") then
2169 call MOM_error(FATAL, "MOM_surface_forcing (surface_forcing_init): "//&
2170 'WIND_CONFIG = "SCM_ideal_hurr" is a depricated option. '//&
2171 'To obtain mathematically equivalent results set '//&
21720 'WIND_CONFIG = "ideal_hurr", IDL_HURR_SCM = True and IDL_HURR_X0 = 6.48e+05.')
21731 elseif (trim(CS%wind_config) == "const") then
2174 call get_param(param_file, mdl, "CONST_WIND_TAUX", CS%tau_x0, &
2175 "With wind_config const, this is the constant zonal wind-stress", &
21760 units="Pa", scale=US%Pa_to_RLZ_T2, fail_if_missing=.true.)
2177 call get_param(param_file, mdl, "CONST_WIND_TAUY", CS%tau_y0, &
2178 "With wind_config const, this is the constant meridional wind-stress", &
21790 units="Pa", scale=US%Pa_to_RLZ_T2, fail_if_missing=.true.)
21801 elseif (trim(CS%wind_config) == "SCM_CVmix_tests" .or. &
2181 trim(CS%buoy_config) == "SCM_CVmix_tests") then
21820 call SCM_CVmix_tests_surface_forcing_init(Time, G, param_file, CS%SCM_CVmix_tests_CSp)
2183 endif
2184
2185 ! Set up MARBL forcing control structure
2186 call MARBL_forcing_init(G, US, param_file, diag, Time, CS%inputdir, CS%use_marbl_tracers, &
21871 CS%marbl_forcing_CSp)
2188
21891 call register_forcing_type_diags(Time, diag, US, CS%use_temperature, CS%handles)
2190
2191 ! Set up any restart fields associated with the forcing.
21921 call restart_init(param_file, CS%restart_CSp, "MOM_forcing.res")
2193!#CTRL# call register_ctrl_forcing_restarts(G, param_file, CS%ctrl_forcing_CSp, &
2194!#CTRL# CS%restart_CSp)
21951 call restart_init_end(CS%restart_CSp)
2196
21971 if (associated(CS%restart_CSp)) then
21980 call Get_MOM_Input(dirs=dirs)
2199
22000 new_sim = .false.
22010 if ((dirs%input_filename(1:1) == 'n') .and. &
22020 (LEN_TRIM(dirs%input_filename) == 1)) new_sim = .true.
22030 if (.not.new_sim) then
2204 call restore_state(dirs%input_filename, dirs%restart_input_dir, Time_frc, &
22050 G, CS%restart_CSp)
2206 endif
2207 endif
2208
2209 ! Determine how many time levels are in each forcing variable.
22101 if (trim(CS%buoy_config) == "file") then
22110 CS%SW_nlev = num_timelevels(CS%shortwave_file, CS%SW_var, min_dims=3)
22120 CS%LW_nlev = num_timelevels(CS%longwave_file, CS%LW_var, min_dims=3)
22130 CS%latent_nlev = num_timelevels(CS%latentheat_file, CS%latent_var, 3)
22140 CS%sens_nlev = num_timelevels(CS%sensibleheat_file, CS%sens_var, min_dims=3)
2215
22160 CS%evap_nlev = num_timelevels(CS%evaporation_file, CS%evap_var, min_dims=3)
22170 CS%precip_nlev = num_timelevels(CS%rain_file, CS%rain_var, min_dims=3)
22180 CS%runoff_nlev = num_timelevels(CS%runoff_file, CS%lrunoff_var, 3)
2219
22200 CS%SST_nlev = num_timelevels(CS%SSTrestore_file, CS%SST_restore_var, 3)
22210 CS%SSS_nlev = num_timelevels(CS%salinityrestore_file, CS%SSS_restore_var, 3)
2222 endif
2223
22241 if (trim(CS%wind_config) == "file") &
22250 CS%wind_nlev = num_timelevels(CS%wind_file, CS%stress_x_var, min_dims=3)
2226
2227!#CTRL# call controlled_forcing_init(Time, G, US, param_file, diag, CS%ctrl_forcing_CSp)
2228
22291 call user_revise_forcing_init(param_file, CS%urf_CS)
2230
22311 call cpu_clock_end(id_clock_forcing)
22321end subroutine surface_forcing_init
2233
2234
2235!> Deallocate memory associated with the surface forcing module
22360subroutine surface_forcing_end(CS, fluxes)
2237 type(surface_forcing_CS), pointer :: CS !< pointer to control structure returned by
2238 !! a previous surface_forcing_init call
2239 type(forcing), optional, intent(inout) :: fluxes !< A structure containing thermodynamic forcing fields
2240
22410 if (present(fluxes)) call deallocate_forcing_type(fluxes)
2242
2243!#CTRL# call controlled_forcing_end(CS%ctrl_forcing_CSp)
2244
22450 if (associated(CS)) deallocate(CS)
22460 CS => NULL()
2247
22480 call callTree_leave("MARBL_forcing_from_data_override, MOM_surface_forcing.F90")
22490end subroutine surface_forcing_end
2250
22510end module MOM_surface_forcing