MOM6
dumbbell_surface_forcing.F90
1 !> Surface forcing for the dumbbell test case
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use mom_diag_mediator, only : post_data, query_averaging_enabled
7 use mom_diag_mediator, only : register_diag_field, diag_ctrl
8 use mom_domains, only : pass_var, pass_vector, agrid
9 use mom_error_handler, only : mom_error, fatal, warning, is_root_pe
12 use mom_grid, only : ocean_grid_type
13 use mom_io, only : file_exists, read_data
15 use mom_time_manager, only : time_type, operator(+), operator(/), get_time
16 use mom_tracer_flow_control, only : call_tracer_set_forcing
19 use mom_variables, only : surface
20 
21 implicit none ; private
22 
23 public dumbbell_dynamic_forcing, dumbbell_buoyancy_forcing, dumbbell_surface_forcing_init
24 
25 !> Control structure for the dumbbell test case forcing
26 type, public :: dumbbell_surface_forcing_cs ; private
27  logical :: use_temperature !< If true, temperature and salinity are used as state variables.
28  logical :: restorebuoy !< If true, use restoring surface buoyancy forcing.
29  real :: rho0 !< The density used in the Boussinesq approximation [R ~> kg m-3].
30  real :: g_earth !< The gravitational acceleration [L2 Z-1 T-2 ~> m s-2]
31  real :: flux_const !< The restoring rate at the surface [Z T-1 ~> m s-1].
32 ! real :: gust_const !< A constant unresolved background gustiness
33 ! !! that contributes to ustar [R L Z T-2 ~> Pa].
34  real :: slp_amplitude !< The amplitude of pressure loading [R L2 T-2 ~> Pa] applied
35  !! to the reservoirs
36  real :: slp_period !< Period of sinusoidal pressure wave [days]
37  real, dimension(:,:), allocatable :: &
38  forcing_mask !< A mask regulating where forcing occurs
39  real, dimension(:,:), allocatable :: &
40  s_restore !< The surface salinity field toward which to restore [ppt].
41  type(diag_ctrl), pointer :: diag => null() !< A structure that is used to regulate the
42  !! timing of diagnostic output.
44 
45 contains
46 
47 !> Surface buoyancy (heat and fresh water) fluxes for the dumbbell test case
48 subroutine dumbbell_buoyancy_forcing(sfc_state, fluxes, day, dt, G, US, CS)
49  type(surface), intent(inout) :: sfc_state !< A structure containing fields that
50  !! describe the surface state of the ocean.
51  type(forcing), intent(inout) :: fluxes !< A structure containing pointers to any
52  !! possible forcing fields. Unused fields
53  !! have NULL ptrs.
54  type(time_type), intent(in) :: day !< Time of the fluxes.
55  real, intent(in) :: dt !< The amount of time over which
56  !! the fluxes apply [s]
57  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
58  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
59  type(dumbbell_surface_forcing_cs), pointer :: cs !< A control structure returned by a previous
60  !! call to dumbbell_surface_forcing_init
61  ! Local variables
62  real :: temp_restore ! The temperature that is being restored toward [degC].
63  real :: salin_restore ! The salinity that is being restored toward [ppt].
64  integer :: i, j, is, ie, js, je
65  integer :: isd, ied, jsd, jed
66 
67  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
68  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
69 
70 
71  ! Allocate and zero out the forcing arrays, as necessary.
72  if (cs%use_temperature) then
73  call safe_alloc_ptr(fluxes%evap, isd, ied, jsd, jed)
74  call safe_alloc_ptr(fluxes%lprec, isd, ied, jsd, jed)
75  call safe_alloc_ptr(fluxes%fprec, isd, ied, jsd, jed)
76  call safe_alloc_ptr(fluxes%lrunoff, isd, ied, jsd, jed)
77  call safe_alloc_ptr(fluxes%frunoff, isd, ied, jsd, jed)
78  call safe_alloc_ptr(fluxes%vprec, isd, ied, jsd, jed)
79 
80  call safe_alloc_ptr(fluxes%sw, isd, ied, jsd, jed)
81  call safe_alloc_ptr(fluxes%lw, isd, ied, jsd, jed)
82  call safe_alloc_ptr(fluxes%latent, isd, ied, jsd, jed)
83  call safe_alloc_ptr(fluxes%sens, isd, ied, jsd, jed)
84  else ! This is the buoyancy only mode.
85  call safe_alloc_ptr(fluxes%buoy, isd, ied, jsd, jed)
86  endif
87 
88 
89  ! MODIFY THE CODE IN THE FOLLOWING LOOPS TO SET THE BUOYANCY FORCING TERMS.
90 
91  if ( cs%use_temperature ) then
92  ! Set whichever fluxes are to be used here. Any fluxes that
93  ! are always zero do not need to be changed here.
94  do j=js,je ; do i=is,ie
95  ! Fluxes of fresh water through the surface are in units of [R Z T-1 ~> kg m-2 s-1]
96  ! and are positive downward - i.e. evaporation should be negative.
97  fluxes%evap(i,j) = -0.0 * g%mask2dT(i,j)
98  fluxes%lprec(i,j) = 0.0 * g%mask2dT(i,j)
99 
100  ! vprec will be set later, if it is needed for salinity restoring.
101  fluxes%vprec(i,j) = 0.0
102 
103  ! Heat fluxes are in units of [Q R Z T-1 ~> W m-2] and are positive into the ocean.
104  fluxes%lw(i,j) = 0.0 * g%mask2dT(i,j)
105  fluxes%latent(i,j) = 0.0 * g%mask2dT(i,j)
106  fluxes%sens(i,j) = 0.0 * g%mask2dT(i,j)
107  fluxes%sw(i,j) = 0.0 * g%mask2dT(i,j)
108  enddo ; enddo
109  else ! This is the buoyancy only mode.
110  do j=js,je ; do i=is,ie
111  ! fluxes%buoy is the buoyancy flux into the ocean [L2 T-3 ~> m2 s-3]. A positive
112  ! buoyancy flux is of the same sign as heating the ocean.
113  fluxes%buoy(i,j) = 0.0 * g%mask2dT(i,j)
114  enddo ; enddo
115  endif
116 
117  if (cs%use_temperature .and. cs%restorebuoy) then
118  do j=js,je ; do i=is,ie
119  if (cs%forcing_mask(i,j)>0.) then
120  fluxes%vprec(i,j) = - (g%mask2dT(i,j) * (cs%Rho0*cs%Flux_const)) * &
121  ((cs%S_restore(i,j) - sfc_state%SSS(i,j)) / (0.5 * (cs%S_restore(i,j) + sfc_state%SSS(i,j))))
122 
123  endif
124  enddo ; enddo
125  endif
126 
127 end subroutine dumbbell_buoyancy_forcing
128 
129 !> Dynamic forcing for the dumbbell test case
130 subroutine dumbbell_dynamic_forcing(sfc_state, fluxes, day, dt, G, CS)
131  type(surface), intent(inout) :: sfc_state !< A structure containing fields that
132  !! describe the surface state of the ocean.
133  type(forcing), intent(inout) :: fluxes !< A structure containing pointers to any
134  !! possible forcing fields. Unused fields
135  !! have NULL ptrs.
136  type(time_type), intent(in) :: day !< Time of the fluxes.
137  real, intent(in) :: dt !< The amount of time over which
138  !! the fluxes apply [s]
139  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
140  type(dumbbell_surface_forcing_cs), pointer :: cs !< A control structure returned by a previous
141  !! call to dumbbell_surface_forcing_init
142  ! Local variables
143  integer :: i, j, is, ie, js, je
144  integer :: isd, ied, jsd, jed
145  integer :: idays, isecs
146  real :: deg_rad, rdays
147 
148 
149  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
150  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
151 
152  deg_rad = atan(1.0)*4.0/180.
153 
154  call get_time(day,isecs,idays)
155  rdays = real(idays) + real(isecs)/8.64e4
156  ! This could be: rdays = time_type_to_real(day)/8.64e4
157 
158  ! Allocate and zero out the forcing arrays, as necessary.
159  call safe_alloc_ptr(fluxes%p_surf, isd, ied, jsd, jed)
160  call safe_alloc_ptr(fluxes%p_surf_full, isd, ied, jsd, jed)
161 
162  do j=js,je ; do i=is,ie
163  fluxes%p_surf(i,j) = cs%forcing_mask(i,j)* cs%slp_amplitude * &
164  g%mask2dT(i,j) * sin(deg_rad*(rdays/cs%slp_period))
165  fluxes%p_surf_full(i,j) = cs%forcing_mask(i,j) * cs%slp_amplitude * &
166  g%mask2dT(i,j) * sin(deg_rad*(rdays/cs%slp_period))
167  enddo ; enddo
168 
169 end subroutine dumbbell_dynamic_forcing
170 
171 !> Reads and sets up the forcing for the dumbbell test case
172 subroutine dumbbell_surface_forcing_init(Time, G, US, param_file, diag, CS)
173  type(time_type), intent(in) :: time !< The current model time.
174  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
175  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
176  type(param_file_type), intent(in) :: param_file !< A structure to parse for run-time parameters
177  type(diag_ctrl), target, intent(in) :: diag !< A structure that is used to
178  !! regulate diagnostic output.
180  pointer :: cs !< A pointer to the control structure for this module
181  ! Local variables
182  real :: s_surf, s_range
183  real :: x, y
184  integer :: i, j
185  logical :: dbrotate ! If true, rotate the domain.
186 #include "version_variable.h"
187  character(len=40) :: mdl = "dumbbell_surface_forcing" ! This module's name.
188 
189  if (associated(cs)) then
190  call mom_error(warning, "dumbbell_surface_forcing_init called with an associated "// &
191  "control structure.")
192  return
193  endif
194  allocate(cs)
195  cs%diag => diag
196 
197  ! Read all relevant parameters and write them to the model log.
198  call log_version(param_file, mdl, version, "")
199  call get_param(param_file, mdl, "ENABLE_THERMODYNAMICS", cs%use_temperature, &
200  "If true, Temperature and salinity are used as state variables.", default=.true.)
201 
202  call get_param(param_file, mdl, "G_EARTH", cs%G_Earth, &
203  "The gravitational acceleration of the Earth.", &
204  units="m s-2", default = 9.80, scale=us%m_to_L**2*us%Z_to_m*us%T_to_s**2)
205  call get_param(param_file, mdl, "RHO_0", cs%Rho0, &
206  "The mean ocean density used with BOUSSINESQ true to "//&
207  "calculate accelerations and the mass for conservation "//&
208  "properties, or with BOUSSINSEQ false to convert some "//&
209  "parameters from vertical units of m to kg m-2.", &
210  units="kg m-3", default=1035.0, scale=us%kg_m3_to_R)
211  call get_param(param_file, mdl, "DUMBBELL_SLP_AMP", cs%slp_amplitude, &
212  "Amplitude of SLP forcing in reservoirs.", &
213  units="Pa", default = 10000.0, scale=us%kg_m3_to_R*us%m_s_to_L_T**2)
214  call get_param(param_file, mdl, "DUMBBELL_SLP_PERIOD", cs%slp_period, &
215  "Periodicity of SLP forcing in reservoirs.", &
216  units="days", default = 1.0)
217  call get_param(param_file, mdl, "DUMBBELL_ROTATION", dbrotate, &
218  'Logical for rotation of dumbbell domain.',&
219  units='nondim', default=.false., do_not_log=.true.)
220  call get_param(param_file, mdl,"INITIAL_SSS", s_surf, &
221  "Initial surface salinity", units="1e-3", default=34.0, do_not_log=.true.)
222  call get_param(param_file, mdl,"INITIAL_S_RANGE", s_range, &
223  "Initial salinity range (bottom - surface)", units="1e-3", &
224  default=2., do_not_log=.true.)
225 
226  call get_param(param_file, mdl, "RESTOREBUOY", cs%restorebuoy, &
227  "If true, the buoyancy fluxes drive the model back "//&
228  "toward some specified surface state with a rate "//&
229  "given by FLUXCONST.", default= .false.)
230  if (cs%restorebuoy) then
231  call get_param(param_file, mdl, "FLUXCONST", cs%Flux_const, &
232  "The constant that relates the restoring surface fluxes to the relative "//&
233  "surface anomalies (akin to a piston velocity). Note the non-MKS units.", &
234  default=0.0, units="m day-1", scale=us%m_to_Z*us%T_to_s)
235  ! Convert CS%Flux_const from m day-1 to m s-1.
236  cs%Flux_const = cs%Flux_const / 86400.0
237 
238 
239  allocate(cs%forcing_mask(g%isd:g%ied, g%jsd:g%jed)); cs%forcing_mask(:,:)=0.0
240  allocate(cs%S_restore(g%isd:g%ied, g%jsd:g%jed))
241 
242  do j=g%jsc,g%jec
243  do i=g%isc,g%iec
244  ! Compute normalized zonal coordinates (x,y=0 at center of domain)
245 ! x = ( G%geoLonT(i,j) - G%west_lon ) / G%len_lon - 0.5
246 ! y = ( G%geoLatT(i,j) - G%south_lat ) / G%len_lat - 0.5
247  if (dbrotate) then
248  ! This is really y in the rotated case
249  x = ( g%geoLatT(i,j) - g%south_lat ) / g%len_lat - 0.5
250  else
251  x = ( g%geoLonT(i,j) - g%west_lon ) / g%len_lon - 0.5
252  endif
253  cs%forcing_mask(i,j)=0
254  cs%S_restore(i,j) = s_surf
255  if ((x>0.25)) then
256  cs%forcing_mask(i,j) = 1
257  cs%S_restore(i,j) = s_surf + s_range
258  elseif ((x<-0.25)) then
259  cs%forcing_mask(i,j) = 1
260  cs%S_restore(i,j) = s_surf - s_range
261  endif
262  enddo
263  enddo
264  endif
265 
266 end subroutine dumbbell_surface_forcing_init
267 
268 end module dumbbell_surface_forcing
Pointers to various fields which may be used describe the surface state of MOM, and which will be ret...
Wraps the FMS time manager functions.
This module implements boundary forcing for MOM6.
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26
The following data type a list of diagnostic fields an their variants, as well as variables that cont...
Surface forcing for the dumbbell test case.
A structure that can be parsed to read and document run-time parameters.
Provides the ocean grid type.
Definition: MOM_grid.F90:2
Control structure for the dumbbell test case forcing.
This module contains I/O framework code.
Definition: MOM_io.F90:2
The MOM6 facility to parse input files for runtime parameters.
Do a halo update on a pair of arrays representing the two components of a vector. ...
Definition: MOM_domains.F90:59
Orchestrates the registration and calling of tracer packages.
Allocate the fields of a (flux) forcing type, based on either a set of input flags for each group of ...
Allocate a pointer to a 1-d, 2-d or 3-d array.
Make a diagnostic available for averaging or output.
Describes various unit conversion factors.
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Convenience functions for safely allocating memory without accidentally reallocating pointer and caus...
Describes the decomposed MOM domain and has routines for communications across PEs.
Definition: MOM_domains.F90:2
The subroutines here provide convenient wrappers to the fms diag_manager interfaces with additional d...
Routines for error handling and I/O management.
The control structure for orchestrating the calling of tracer packages.
Structure that contains pointers to the boundary forcing used to drive the liquid ocean simulated by ...
An overloaded interface to log version information about modules.
Indicate whether a file exists, perhaps with domain decomposition.
Definition: MOM_io.F90:68
Provides transparent structures with groups of MOM6 variables and supporting routines.
Do a halo update on an array.
Definition: MOM_domains.F90:54
An overloaded interface to read and log the values of various types of parameters.