MOM6
Phillips_initialization.F90
1 !> Initialization for the "Phillips" channel configuration
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
6 use mom_error_handler, only : mom_mesg, mom_error, fatal, is_root_pe
9 use mom_get_input, only : directories
10 use mom_grid, only : ocean_grid_type
11 use mom_sponge, only : set_up_sponge_field, initialize_sponge, sponge_cs
17 
18 implicit none ; private
19 
20 #include <MOM_memory.h>
21 
22 public phillips_initialize_thickness
23 public phillips_initialize_velocity
24 public phillips_initialize_sponges
25 public phillips_initialize_topography
26 
27 ! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
28 ! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
29 ! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
30 ! vary with the Boussinesq approximation, the Boussinesq variant is given first.
31 
32 ! This include declares and sets the variable "version".
33 #include "version_variable.h"
34 
35 contains
36 
37 !> Initialize the thickness field for the Phillips model test case.
38 subroutine phillips_initialize_thickness(h, G, GV, US, param_file, just_read_params)
39  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
40  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure.
41  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
42  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), &
43  intent(out) :: h !< The thickness that is being initialized [H ~> m or kg m-2]
44  type(param_file_type), intent(in) :: param_file !< A structure indicating the open file
45  !! to parse for model parameter values.
46  logical, optional, intent(in) :: just_read_params !< If present and true, this call will
47  !! only read parameters without changing h.
48 
49  real :: eta0(szk_(g)+1) ! The 1-d nominal positions of the interfaces [Z ~> m]
50  real :: eta_im(szj_(g),szk_(g)+1) ! A temporary array for zonal-mean eta [Z ~> m]
51  real :: eta1d(szk_(g)+1) ! Interface height relative to the sea surface, positive upward [Z ~> m]
52  real :: jet_width ! The width of the zonal-mean jet [km]
53  real :: jet_height ! The interface height scale associated with the zonal-mean jet [Z ~> m]
54  real :: y_2
55  real :: half_strat ! The fractional depth where the stratification is centered [nondim]
56  real :: half_depth ! The depth where the stratification is centered [Z ~> m]
57  logical :: just_read ! If true, just read parameters but set nothing.
58  character(len=40) :: mdl = "Phillips_initialize_thickness" ! This subroutine's name.
59  integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz
60 
61  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
62  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
63 
64  eta_im(:,:) = 0.0
65 
66  just_read = .false. ; if (present(just_read_params)) just_read = just_read_params
67 
68  if (.not.just_read) call log_version(param_file, mdl, version)
69  call get_param(param_file, mdl, "HALF_STRAT_DEPTH", half_strat, &
70  "The fractional depth where the stratification is centered.", &
71  units="nondim", default = 0.5, do_not_log=just_read)
72  call get_param(param_file, mdl, "JET_WIDTH", jet_width, &
73  "The width of the zonal-mean jet.", units="km", &
74  fail_if_missing=.not.just_read, do_not_log=just_read)
75  call get_param(param_file, mdl, "JET_HEIGHT", jet_height, &
76  "The interface height scale associated with the "//&
77  "zonal-mean jet.", units="m", scale=us%m_to_Z, &
78  fail_if_missing=.not.just_read, do_not_log=just_read)
79 
80  if (just_read) return ! All run-time parameters have been read, so return.
81 
82  half_depth = g%max_depth*half_strat
83  eta0(1) = 0.0 ; eta0(nz+1) = -g%max_depth
84  do k=2,1+nz/2 ; eta0(k) = -half_depth*(2.0*(k-1)/real(nz)) ; enddo
85  do k=2+nz/2,nz+1
86  eta0(k) = -g%max_depth - 2.0*(g%max_depth-half_depth) * ((k-(nz+1))/real(nz))
87  enddo
88 
89  do j=js,je
90  eta_im(j,1) = 0.0 ; eta_im(j,nz+1) = -g%max_depth
91  enddo
92  do k=2,nz ; do j=js,je
93  y_2 = g%geoLatT(is,j) - g%south_lat - 0.5*g%len_lat
94  eta_im(j,k) = eta0(k) + jet_height * tanh(y_2 / jet_width)
95  ! or ... + jet_height * atan(y_2 / jet_width)
96  if (eta_im(j,k) > 0.0) eta_im(j,k) = 0.0
97  if (eta_im(j,k) < -g%max_depth) eta_im(j,k) = -g%max_depth
98  enddo ; enddo
99 
100  do j=js,je ; do i=is,ie
101  ! This sets the initial thickness in [H ~> m or kg m-2] of the layers. The
102  ! thicknesses are set to insure that: 1. each layer is at least an Angstrom thick, and
103  ! 2. the interfaces are where they should be based on the resting depths and interface
104  ! height perturbations, as long at this doesn't interfere with 1.
105  eta1d(nz+1) = -g%bathyT(i,j)
106  do k=nz,1,-1
107  eta1d(k) = eta_im(j,k)
108  if (eta1d(k) < (eta1d(k+1) + gv%Angstrom_Z)) then
109  eta1d(k) = eta1d(k+1) + gv%Angstrom_Z
110  h(i,j,k) = gv%Angstrom_H
111  else
112  h(i,j,k) = gv%Z_to_H * (eta1d(k) - eta1d(k+1))
113  endif
114  enddo
115  enddo ; enddo
116 
117 end subroutine phillips_initialize_thickness
118 
119 !> Initialize the velocity fields for the Phillips model test case
120 subroutine phillips_initialize_velocity(u, v, G, GV, US, param_file, just_read_params)
121  type(ocean_grid_type), intent(in) :: g !< Grid structure
122  type(verticalgrid_type), intent(in) :: gv !< Vertical grid structure
123  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
124  real, dimension(SZIB_(G),SZJ_(G),SZK_(G)), &
125  intent(out) :: u !< i-component of velocity [m s-1]
126  real, dimension(SZI_(G),SZJB_(G),SZK_(G)), &
127  intent(out) :: v !< j-component of velocity [m s-1]
128  type(param_file_type), intent(in) :: param_file !< A structure indicating the open file to
129  !! parse for modelparameter values.
130  logical, optional, intent(in) :: just_read_params !< If present and true, this call will
131  !! only read parameters without changing h.
132 
133  real :: jet_width, jet_height, x_2, y_2
134  real :: velocity_amplitude, pi
135  integer :: i, j, k, is, ie, js, je, nz, m
136  logical :: just_read ! If true, just read parameters but set nothing.
137  character(len=40) :: mdl = "Phillips_initialize_velocity" ! This subroutine's name.
138  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
139 
140  just_read = .false. ; if (present(just_read_params)) just_read = just_read_params
141 
142  if (.not.just_read) call log_version(param_file, mdl, version)
143  call get_param(param_file, mdl, "VELOCITY_IC_PERTURB_AMP", velocity_amplitude, &
144  "The magnitude of the initial velocity perturbation.", &
145  units="m s-1", default=0.001, do_not_log=just_read)
146  call get_param(param_file, mdl, "JET_WIDTH", jet_width, &
147  "The width of the zonal-mean jet.", units="km", &
148  fail_if_missing=.not.just_read, do_not_log=just_read)
149  call get_param(param_file, mdl, "JET_HEIGHT", jet_height, &
150  "The interface height scale associated with the "//&
151  "zonal-mean jet.", units="m", scale=us%m_to_Z, &
152  fail_if_missing=.not.just_read, do_not_log=just_read)
153 
154  if (just_read) return ! All run-time parameters have been read, so return.
155 
156  u(:,:,:) = 0.0
157  v(:,:,:) = 0.0
158 
159  pi = 4.0*atan(1.0)
160 
161  ! Use thermal wind shear to give a geostrophically balanced flow.
162  do k=nz-1,1 ; do j=js,je ; do i=is-1,ie
163  y_2 = g%geoLatCu(i,j) - g%south_lat - 0.5*g%len_lat
164 ! This uses d/d y_2 atan(y_2 / jet_width)
165 ! u(I,j,k) = u(I,j,k+1) + (1e-3 * jet_height / &
166 ! (jet_width * (1.0 + (y_2 / jet_width)**2))) * &
167 ! (2.0 * US%L_to_m**2*US%s_to_T**2*GV%g_prime(K+1) * US%T_to_s / (G%CoriolisBu(I,J) + G%CoriolisBu(I,J-1)))
168 ! This uses d/d y_2 tanh(y_2 / jet_width)
169  u(i,j,k) = u(i,j,k+1) + (1e-3 * (jet_height / jet_width) * &
170  (sech(y_2 / jet_width))**2 ) * &
171  (2.0 * us%L_to_m**2*us%s_to_T**2*gv%g_prime(k+1) * us%T_to_s / (g%CoriolisBu(i,j) + g%CoriolisBu(i,j-1)))
172  enddo ; enddo ; enddo
173 
174  do k=1,nz ; do j=js,je ; do i=is-1,ie
175  y_2 = (g%geoLatCu(i,j) - g%south_lat - 0.5*g%len_lat) / g%len_lat
176  x_2 = (g%geoLonCu(i,j) - g%west_lon - 0.5*g%len_lon) / g%len_lon
177  if (g%geoLonCu(i,j) == g%west_lon) then
178  ! This modification is required so that the perturbations are identical for
179  ! symmetric and non-symmetric memory. It is exactly equivalent to
180  ! taking the longitude at the eastern edge of the domain, so that x_2 ~= 0.5.
181  x_2 = ((g%west_lon + g%len_lon*real(g%ieg-(g%isg-1))/real(g%Domain%niglobal)) - &
182  g%west_lon - 0.5*g%len_lon) / g%len_lon
183  endif
184  u(i,j,k) = u(i,j,k) + velocity_amplitude * ((real(k)-0.5)/real(nz)) * &
185  (0.5 - abs(2.0*x_2) + 0.1*abs(cos(10.0*pi*x_2)) - abs(sin(5.0*pi*y_2)))
186  do m=1,10
187  u(i,j,k) = u(i,j,k) + 0.2*velocity_amplitude * ((real(k)-0.5)/real(nz)) * &
188  cos(2.0*m*pi*x_2 + 2*m) * cos(6.0*pi*y_2)
189  enddo
190  enddo ; enddo ; enddo
191 
192 end subroutine phillips_initialize_velocity
193 
194 !> Sets up the the inverse restoration time (Idamp), and the values towards which the interface
195 !! heights and an arbitrary number of tracers should be restored within each sponge for the Phillips
196 !! model test case
197 subroutine phillips_initialize_sponges(G, GV, US, tv, param_file, CSp, h)
198  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure.
199  type(verticalgrid_type), intent(in) :: gv !< Vertical grid structure
200  type(unit_scale_type), intent(in) :: us !< A dimensional unit scaling type
201  type(thermo_var_ptrs), intent(in) :: tv !< A structure containing pointers
202  !! to any available thermodynamic
203  !! fields, potential temperature and
204  !! salinity or mixed layer density.
205  !! Absent fields have NULL ptrs.
206  type(param_file_type), intent(in) :: param_file !< A structure indicating the
207  !! open file to parse for model
208  !! parameter values.
209  type(sponge_cs), pointer :: csp !< A pointer that is set to point to
210  !! the control structure for the
211  !! sponge module.
212  real, intent(in), dimension(SZI_(G),SZJ_(G),SZK_(GV)) :: h !< Thickness field [H ~> m or kg m-2].
213 
214  ! Local variables
215  real :: eta0(szk_(g)+1) ! The 1-d nominal positions of the interfaces.
216  real :: eta(szi_(g),szj_(g),szk_(g)+1) ! A temporary array for eta [Z ~> m].
217  real :: temp(szi_(g),szj_(g),szk_(g)) ! A temporary array for other variables.
218  real :: idamp(szi_(g),szj_(g)) ! The inverse damping rate [s-1].
219  real :: eta_im(szj_(g),szk_(g)+1) ! A temporary array for zonal-mean eta [Z ~> m].
220  real :: idamp_im(szj_(g)) ! The inverse zonal-mean damping rate [s-1].
221  real :: damp_rate ! The inverse zonal-mean damping rate [s-1].
222  real :: jet_width ! The width of the zonal mean jet, in km.
223  real :: jet_height ! The interface height scale associated with the zonal-mean jet [Z ~> m].
224  real :: y_2 ! The y-position relative to the channel center, in km.
225  real :: half_strat ! The fractional depth where the straficiation is centered [nondim].
226  real :: half_depth ! The depth where the stratification is centered [Z ~> m].
227  character(len=40) :: mdl = "Phillips_initialize_sponges" ! This subroutine's name.
228 
229  integer :: i, j, k, is, ie, js, je, isd, ied, jsd, jed, nz
230  logical, save :: first_call = .true.
231 
232  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec ; nz = g%ke
233  isd = g%isd ; ied = g%ied ; jsd = g%jsd ; jed = g%jed
234 
235  eta(:,:,:) = 0.0 ; temp(:,:,:) = 0.0 ; idamp(:,:) = 0.0
236  eta_im(:,:) = 0.0 ; idamp_im(:) = 0.0
237 
238  if (first_call) call log_version(param_file, mdl, version)
239  first_call = .false.
240  call get_param(param_file, mdl, "HALF_STRAT_DEPTH", half_strat, &
241  "The fractional depth where the stratificaiton is centered.", &
242  units="nondim", default = 0.5)
243  call get_param(param_file, mdl, "SPONGE_RATE", damp_rate, &
244  "The rate at which the zonal-mean sponges damp.", units="s-1", &
245  default = 1.0/(10.0*86400.0))
246 
247  call get_param(param_file, mdl, "JET_WIDTH", jet_width, &
248  "The width of the zonal-mean jet.", units="km", &
249  fail_if_missing=.true.)
250  call get_param(param_file, mdl, "JET_HEIGHT", jet_height, &
251  "The interface height scale associated with the "//&
252  "zonal-mean jet.", units="m", scale=us%m_to_Z, &
253  fail_if_missing=.true.)
254 
255  half_depth = g%max_depth*half_strat
256  eta0(1) = 0.0 ; eta0(nz+1) = -g%max_depth
257  do k=2,1+nz/2 ; eta0(k) = -half_depth*(2.0*(k-1)/real(nz)) ; enddo
258  do k=2+nz/2,nz+1
259  eta0(k) = -g%max_depth - 2.0*(g%max_depth-half_depth) * ((k-(nz+1))/real(nz))
260  enddo
261 
262  do j=js,je
263  idamp_im(j) = damp_rate
264  eta_im(j,1) = 0.0 ; eta_im(j,nz+1) = -g%max_depth
265  enddo
266  do k=2,nz ; do j=js,je
267  y_2 = g%geoLatT(is,j) - g%south_lat - 0.5*g%len_lat
268  eta_im(j,k) = eta0(k) + jet_height * tanh(y_2 / jet_width)
269 ! jet_height * atan(y_2 / jet_width)
270  if (eta_im(j,k) > 0.0) eta_im(j,k) = 0.0
271  if (eta_im(j,k) < -g%max_depth) eta_im(j,k) = -g%max_depth
272  enddo ; enddo
273 
274  call initialize_sponge(idamp, eta, g, param_file, csp, gv, idamp_im, eta_im)
275 
276 end subroutine phillips_initialize_sponges
277 
278 !> sech calculates the hyperbolic secant.
279 function sech(x)
280  real, intent(in) :: x !< Input value.
281  real :: sech !< Result.
282 
283  ! This is here to prevent overflows or underflows.
284  if (abs(x) > 228.) then
285  sech = 0.0
286  else
287  sech = 2.0 / (exp(x) + exp(-x))
288  endif
289 end function sech
290 
291 !> Initialize topography.
292 subroutine phillips_initialize_topography(D, G, param_file, max_depth, US)
293  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
294  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
295  intent(out) :: d !< Ocean bottom depth in m or Z if US is present
296  type(param_file_type), intent(in) :: param_file !< Parameter file structure
297  real, intent(in) :: max_depth !< Maximum model depth in the units of D
298  type(unit_scale_type), optional, intent(in) :: us !< A dimensional unit scaling type
299 
300  ! Local variables
301  real :: m_to_z ! A dimensional rescaling factor.
302  real :: pi, htop, wtop, ltop, offset, dist
303  real :: x1, x2, x3, x4, y1, y2
304  integer :: i,j,is,ie,js,je
305  character(len=40) :: mdl = "Phillips_initialize_topography" ! This subroutine's name.
306 
307  is = g%isc ; ie = g%iec ; js = g%jsc ; je = g%jec
308 
309  pi = 4.0*atan(1.0)
310  m_to_z = 1.0 ; if (present(us)) m_to_z = us%m_to_Z
311 
312  call get_param(param_file, mdl, "PHILLIPS_HTOP", htop, &
313  "The maximum height of the topography.", units="m", scale=m_to_z, &
314  fail_if_missing=.true.)
315 ! Htop=0.375*max_depth ! max height of topog. above max_depth
316  wtop = 0.5*g%len_lat ! meridional width of drake and mount
317  ltop = 0.25*g%len_lon ! zonal width of topographic features
318  offset = 0.1*g%len_lat ! meridional offset from center
319  dist = 0.333*g%len_lon ! distance between drake and mount
320  ! should be longer than Ltop/2
321 
322  y1=g%south_lat+0.5*g%len_lat+offset-0.5*wtop; y2=y1+wtop
323  x1=g%west_lon+0.1*g%len_lon; x2=x1+ltop; x3=x1+dist; x4=x3+3.0/2.0*ltop
324 
325  do i=is,ie ; do j=js,je
326  d(i,j)=0.0
327  if (g%geoLonT(i,j)>x1 .and. g%geoLonT(i,j)<x2) then
328  d(i,j) = htop*sin(pi*(g%geoLonT(i,j)-x1)/(x2-x1))**2
329  if (g%geoLatT(i,j)>y1 .and. g%geoLatT(i,j)<y2) then
330  d(i,j) = d(i,j)*(1-sin(pi*(g%geoLatT(i,j)-y1)/(y2-y1))**2)
331  endif
332  elseif (g%geoLonT(i,j)>x3 .and. g%geoLonT(i,j)<x4 .and. &
333  g%geoLatT(i,j)>y1 .and. g%geoLatT(i,j)<y2) then
334  d(i,j) = 2.0/3.0*htop*sin(pi*(g%geoLonT(i,j)-x3)/(x4-x3))**2 &
335  *sin(pi*(g%geoLatT(i,j)-y1)/(y2-y1))**2
336  endif
337  d(i,j) = max_depth - d(i,j)
338  enddo ; enddo
339 
340 end subroutine phillips_initialize_topography
341 
342 !> \namespace phillips_initialization
343 !!
344 !! By Robert Hallberg, April 1994 - June 2002
345 !!
346 !! This subroutine initializes the fields for the simulations.
347 !! The one argument passed to initialize, Time, is set to the
348 !! current time of the simulation. The fields which are initialized
349 !! here are:
350 !! u - Zonal velocity [m s-1].
351 !! v - Meridional velocity [m s-1].
352 !! h - Layer thickness in m. (Must be positive.)
353 !! D - Basin depth in m. (Must be positive.)
354 !! f - The Coriolis parameter [s-1].
355 !! g - The reduced gravity at each interface [m s-2]
356 !! Rlay - Layer potential density (coordinate variable) [kg m-3].
357 !! If ENABLE_THERMODYNAMICS is defined:
358 !! T - Temperature [degC].
359 !! S - Salinity [ppt].
360 !! If SPONGE is defined:
361 !! A series of subroutine calls are made to set up the damping
362 !! rates and reference profiles for all variables that are damped
363 !! in the sponge.
364 !! Any user provided tracer code is also first linked through this
365 !! subroutine.
366 !!
367 !! Forcing-related fields (taux, tauy, buoy, ustar, etc.) are set
368 !! in MOM_surface_forcing.F90.
369 !!
370 !! These variables are all set in the set of subroutines (in this
371 !! file) Phillips_initialize_thickness, Phillips_initialize_velocity,
372 !! Phillips_initialize_topography and Phillips_initialize_sponges
373 !! that seet up fields that are specific to the Phillips instability
374 !! test case.
375 
376 end module phillips_initialization
mom_verticalgrid
Provides a transparent vertical ocean grid type and supporting routines.
Definition: MOM_verticalGrid.F90:2
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_variables::thermo_var_ptrs
Pointers to an assortment of thermodynamic fields that may be available, including potential temperat...
Definition: MOM_variables.F90:82
mom_get_input::directories
Container for paths and parameter file names.
Definition: MOM_get_input.F90:20
mom_dyn_horgrid
Contains a shareable dynamic type for describing horizontal grids and metric data and utilty routines...
Definition: MOM_dyn_horgrid.F90:3
mom_eos
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
mom_tracer_registry
This module contains the tracer_registry_type and the subroutines that handle registration of tracers...
Definition: MOM_tracer_registry.F90:5
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
mom_get_input
Reads the only Fortran name list needed to boot-strap the model.
Definition: MOM_get_input.F90:6
mom_unit_scaling::unit_scale_type
Describes various unit conversion factors.
Definition: MOM_unit_scaling.F90:14
mom_eos::eos_type
A control structure for the equation of state.
Definition: MOM_EOS.F90:86
mom_verticalgrid::verticalgrid_type
Describes the vertical ocean grid, including unit conversion factors.
Definition: MOM_verticalGrid.F90:24
mom_variables
Provides transparent structures with groups of MOM6 variables and supporting routines.
Definition: MOM_variables.F90:2
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_sponge
Implements sponge regions in isopycnal mode.
Definition: MOM_sponge.F90:2
mom_eos::calculate_density_derivs
Calculate the derivatives of density with temperature and salinity from T, S, and P.
Definition: MOM_EOS.F90:70
mom_tracer_registry::tracer_registry_type
Type to carry basic tracer information.
Definition: MOM_tracer_registry.F90:122
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_sponge::sponge_cs
This control structure holds memory and parameters for the MOM_sponge module.
Definition: MOM_sponge.F90:40
mom_unit_scaling
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Definition: MOM_unit_scaling.F90:2
phillips_initialization
Initialization for the "Phillips" channel configuration.
Definition: Phillips_initialization.F90:2
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_dyn_horgrid::dyn_horgrid_type
Describes the horizontal ocean grid with only dynamic memory arrays.
Definition: MOM_dyn_horgrid.F90:22
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:25
mom_eos::calculate_density
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:60