← back to index

src/ALE/coord_zlike.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!> Regrid columns for a z-like coordinate (z-star, z-level)
6module coord_zlike
7
8use MOM_error_handler, only : MOM_error, FATAL
9
10implicit none ; private
11
12!> Control structure containing required parameters for a z-like coordinate
13type, public :: zlike_CS ; private
14
15 !> Number of levels to be generated
16 integer :: nk
17
18 !> Minimum thickness allowed for layers, in the same thickness units (perhaps [H ~> m or kg m-2])
19 !! that will be used in all subsequent calls to build_zstar_column with this structure.
20 real :: min_thickness
21
22 !> Target coordinate resolution, usually in [Z ~> m]
23 real, allocatable, dimension(:) :: coordinateResolution
24end type zlike_CS
25
26public init_coord_zlike, set_zlike_params, build_zstar_column, end_coord_zlike
27
28contains
29
30!> Initialise a zlike_CS with pointers to parameters
311subroutine init_coord_zlike(CS, nk, coordinateResolution)
32 type(zlike_CS), pointer :: CS !< Unassociated pointer to hold the control structure
33 integer, intent(in) :: nk !< Number of levels in the grid
34 real, dimension(:), intent(in) :: coordinateResolution !< Target coordinate resolution [Z ~> m]
35
361 if (associated(CS)) call MOM_error(FATAL, "init_coord_zlike: CS already associated!")
371 allocate(CS)
381 allocate(CS%coordinateResolution(nk))
39
401 CS%nk = nk
4135 CS%coordinateResolution = coordinateResolution
421end subroutine init_coord_zlike
43
44!> Deallocates the zlike control structure
451subroutine end_coord_zlike(CS)
46 type(zlike_CS), pointer :: CS !< Coordinate control structure
47
48 ! Nothing to do
491 if (.not. associated(CS)) return
501 deallocate(CS%coordinateResolution)
511 deallocate(CS)
52end subroutine end_coord_zlike
53
54!> Set parameters in the zlike structure
552subroutine set_zlike_params(CS, min_thickness)
56 type(zlike_CS), pointer :: CS !< Coordinate control structure
57 real, optional, intent(in) :: min_thickness !< Minimum allowed thickness [H ~> m or kg m-2]
58
592 if (.not. associated(CS)) call MOM_error(FATAL, "set_zlike_params: CS not associated")
60
612 if (present(min_thickness)) CS%min_thickness = min_thickness
622end subroutine set_zlike_params
63
64!> Builds a z* coordinate with a minimum thickness
6546370subroutine build_zstar_column(CS, depth, total_thickness, zInterface, &
66 z_rigid_top, eta_orig, zScale)
67 type(zlike_CS), intent(in) :: CS !< Coordinate control structure
68 real, intent(in) :: depth !< Depth of ocean bottom (positive downward in the
69 !! output units), units may be [Z ~> m] or [H ~> m or kg m-2]
70 real, intent(in) :: total_thickness !< Column thickness (positive definite in the same
71 !! units as depth) [Z ~> m] or [H ~> m or kg m-2]
72 real, dimension(CS%nk+1), intent(inout) :: zInterface !< Absolute positions of interfaces (in the same
73 !! units as depth) [Z ~> m] or [H ~> m or kg m-2]
74 real, optional, intent(in) :: z_rigid_top !< The height of a rigid top (positive upward in the same
75 !! units as depth) [Z ~> m] or [H ~> m or kg m-2]
76 real, optional, intent(in) :: eta_orig !< The actual original height of the top (in the same
77 !! units as depth) [Z ~> m] or [H ~> m or kg m-2]
78 real, optional, intent(in) :: zScale !< Scaling factor from the target coordinate resolution
79 !! in Z to desired units for zInterface, perhaps Z_to_H,
80 !! often [nondim] or [H Z-1 ~> 1 or kg m-3]
81 ! Local variables
82 real :: eta ! Free surface height [Z ~> m] or [H ~> m or kg m-2]
83 real :: stretching ! A stretching factor for the coordinate [nondim]
84 real :: dh, min_thickness, z0_top, z_star, z_scale ! Thicknesses or heights [Z ~> m] or [H ~> m or kg m-2]
85 integer :: k
86 logical :: new_zstar_def
87
8846370 z_scale = 1.0 ; if (present(zScale)) z_scale = zScale
89
9046370 new_zstar_def = .false.
9146370 min_thickness = min( CS%min_thickness, total_thickness/real(CS%nk) )
9246370 z0_top = 0.
9346370 if (present(z_rigid_top)) then
940 z0_top = z_rigid_top
950 new_zstar_def = .true.
96 endif
97
98 ! Position of free-surface (or the rigid top, for which eta ~ z0_top)
9946370 eta = total_thickness - depth
10046370 if (present(eta_orig)) eta = eta_orig
101
102 ! Conventional z* coordinate:
103 ! z* = (z-eta) / stretching where stretching = (H+eta)/H
104 ! z = eta + stretching * z*
105 ! The above gives z*(z=eta) = 0, z*(z=-H) = -H.
106 ! With a rigid top boundary at eta = z0_top then
107 ! z* = z0 + (z-eta) / stretching where stretching = (H+eta)/(H+z0)
108 ! z = eta + stretching * (z*-z0) * stretching
10946370 stretching = total_thickness / ( depth + z0_top )
110
11146370 if (new_zstar_def) then
112 ! z_star is the notional z* coordinate in absence of upper/lower topography
1130 z_star = 0. ! z*=0 at the free-surface
1140 zInterface(1) = eta ! The actual position of the top of the column
1150 do k = 2,CS%nk
1160 z_star = z_star - CS%coordinateResolution(k-1)*z_scale
117 ! This ensures that z is below a rigid upper surface (ice shelf bottom)
1180 zInterface(k) = min( eta + stretching * ( z_star - z0_top ), z0_top )
119 ! This ensures that the layer in inflated
1200 zInterface(k) = min( zInterface(k), zInterface(k-1) - min_thickness )
121 ! This ensures that z is above or at the topography
1220 zInterface(k) = max( zInterface(k), -depth + real(CS%nk+1-k) * min_thickness )
123 enddo
1240 zInterface(CS%nk+1) = -depth
125
126 else
127 ! Integrate down from the top for a notional new grid, ignoring topography
128 ! The starting position is offset by z0_top which, if z0_top<0, will place
129 ! interfaces above the rigid boundary.
13046370 zInterface(1) = eta
1311576580 do k = 1,CS%nk
1321530210 dh = stretching * CS%coordinateResolution(k)*z_scale ! Notional grid spacing
1331576580 zInterface(k+1) = zInterface(k) - dh
134 enddo
135
136 ! Integrating up from the bottom adjusting interface position to accommodate
137 ! inflating layers without disturbing the interface above
13846370 zInterface(CS%nk+1) = -depth
1391576580 do k = CS%nk,1,-1
1401576580 if ( zInterface(k) < (zInterface(k+1) + min_thickness) ) then
141352458 zInterface(k) = zInterface(k+1) + min_thickness
142 endif
143 enddo
144 endif
145
14646370end subroutine build_zstar_column
147
1480end module coord_zlike