MOM6
coord_rho.F90
Go to the documentation of this file.
1 !> Regrid columns for the continuous isopycnal (rho) coordinate
2 module coord_rho
3 
4 use mom_error_handler, only : mom_error, fatal
8 
9 implicit none ; private
10 
11 !> Control structure containing required parameters for the rho coordinate
12 type, public :: rho_cs
13  private
14 
15  !> Number of layers
16  integer :: nk
17 
18  !> Minimum thickness allowed for layers
19  real :: min_thickness
20 
21  !> Reference pressure for density calculations
22  real :: ref_pressure
23 
24  !> If true, integrate for interface positions from the top downward.
25  !! If false, integrate from the bottom upward, as does the rest of the model.
26  logical :: integrate_downward_for_e
27 
28  !> Nominal density of interfaces
29  real, allocatable, dimension(:) :: target_density
30 
31  !> Interpolation control structure
32  type(interp_cs_type) :: interp_cs
33 end type rho_cs
34 
35 !> Maximum number of regridding iterations
36 integer, parameter :: nb_regridding_iterations = 1
37 !> Deviation tolerance between succesive grids in regridding iterations
38 real, parameter :: deviation_tolerance = 1e-10
39 ! This CPP macro embeds some safety checks
40 
42 
43 contains
44 
45 !> Initialise a rho_CS with pointers to parameters
46 subroutine init_coord_rho(CS, nk, ref_pressure, target_density, interp_CS)
47  type(rho_cs), pointer :: CS !< Unassociated pointer to hold the control structure
48  integer, intent(in) :: nk
49  real, intent(in) :: ref_pressure
50  real, dimension(:), intent(in) :: target_density
51  type(interp_cs_type), intent(in) :: interp_CS
52 
53  if (associated(cs)) call mom_error(fatal, "init_coord_rho: CS already associated!")
54  allocate(cs)
55  allocate(cs%target_density(nk+1))
56 
57  cs%nk = nk
58  cs%ref_pressure = ref_pressure
59  cs%target_density(:) = target_density(:)
60  cs%interp_CS = interp_cs
61 end subroutine init_coord_rho
62 
63 subroutine end_coord_rho(CS)
64  type(rho_cs), pointer :: CS
65 
66  ! nothing to do
67  if (.not. associated(cs)) return
68  deallocate(cs%target_density)
69  deallocate(cs)
70 end subroutine end_coord_rho
71 
72 subroutine set_rho_params(CS, min_thickness, integrate_downward_for_e, interp_CS)
73  type(rho_cs), pointer :: CS
74  real, optional, intent(in) :: min_thickness
75  logical, optional, intent(in) :: integrate_downward_for_e
76  type(interp_cs_type), optional, intent(in) :: interp_CS
77 
78  if (.not. associated(cs)) call mom_error(fatal, "set_rho_params: CS not associated")
79 
80  if (present(min_thickness)) cs%min_thickness = min_thickness
81  if (present(integrate_downward_for_e)) cs%integrate_downward_for_e = integrate_downward_for_e
82  if (present(interp_cs)) cs%interp_CS = interp_cs
83 end subroutine set_rho_params
84 
85 subroutine build_rho_column(CS, remapCS, nz, depth, h, T, S, eqn_of_state, zInterface)
86  !< Build a rho coordinate column
87  !!
88  !! The algorithn operates as follows within each column:
89  !!
90  !! 1. Given T & S within each layer, the layer densities are computed.
91  !! 2. Based on these layer densities, a global density profile is reconstructed
92  !! (this profile is monotonically increasing and may be discontinuous)
93  !! 3. The new grid interfaces are determined based on the target interface
94  !! densities.
95  !! 4. T & S are remapped onto the new grid.
96  !! 5. Return to step 1 until convergence or until the maximum number of
97  !! iterations is reached, whichever comes first.
98 
99  type(rho_cs), intent(in) :: CS !< Regridding control structure
100  type(remapping_cs), intent(in) :: remapCS !< Remapping parameters and options
101  integer, intent(in) :: nz !< Number of levels
102  real, intent(in) :: depth !< Depth of ocean bottom (positive in m)
103  real, dimension(nz), intent(in) :: h !< Layer thicknesses, in m
104  real, dimension(nz), intent(in) :: T, S !< T and S for column
105  type(eos_type), pointer :: eqn_of_state !< Equation of state structure
106  real, dimension(nz+1), intent(inout) :: zInterface !< Absolute positions of interfaces
107 
108  ! Local variables
109  integer :: k, m
110  integer :: map_index
111  integer :: k_found
112  integer :: count_nonzero_layers
113  real :: deviation ! When iterating to determine the final
114  ! grid, this is the deviation between two
115  ! successive grids.
116  real :: threshold
117  real :: max_thickness
118  real :: correction
119  real, dimension(nz) :: p, densities, T_tmp, S_tmp, Tmp
120  integer, dimension(nz) :: mapping
121  real :: dh
122  real, dimension(nz) :: h0, h1, hTmp
123  real, dimension(nz+1) :: x0, x1, xTmp
124 
125  threshold = cs%min_thickness
126  p(:) = cs%ref_pressure
127  t_tmp(:) = t(:)
128  s_tmp(:) = s(:)
129  h0(:) = h(:)
130 
131  ! Start iterations to build grid
132  m = 1
133  deviation = 1e10
134  do while ( ( m <= nb_regridding_iterations ) .and. &
135  ( deviation > deviation_tolerance ) )
136 
137  ! Count number of nonzero layers within current water column
138  count_nonzero_layers = 0
139  do k = 1,nz
140  if ( h0(k) > threshold ) then
141  count_nonzero_layers = count_nonzero_layers + 1
142  end if
143  end do
144 
145  ! If there is at most one nonzero layer, stop here (no regridding)
146  if ( count_nonzero_layers <= 1 ) then
147  h1(:) = h0(:)
148  exit ! stop iterations here
149  end if
150 
151  ! Build new grid containing only nonzero layers
152  map_index = 1
153  correction = 0.0
154  do k = 1,nz
155  if ( h0(k) > threshold ) then
156  mapping(map_index) = k
157  htmp(map_index) = h0(k)
158  map_index = map_index + 1
159  else
160  correction = correction + h0(k)
161  end if
162  end do
163 
164  max_thickness = htmp(1)
165  k_found = 1
166  do k = 1,count_nonzero_layers
167  if ( htmp(k) > max_thickness ) then
168  max_thickness = htmp(k)
169  k_found = k
170  end if
171  end do
172 
173  htmp(k_found) = htmp(k_found) + correction
174 
175  xtmp(1) = 0.0
176  do k = 1,count_nonzero_layers
177  xtmp(k+1) = xtmp(k) + htmp(k)
178  end do
179 
180  ! Compute densities within current water column
181  call calculate_density( t_tmp, s_tmp, p, densities,&
182  1, nz, eqn_of_state )
183 
184  do k = 1,count_nonzero_layers
185  densities(k) = densities(mapping(k))
186  end do
187 
188  ! One regridding iteration
189  ! Based on global density profile, interpolate to generate a new grid
190  call build_and_interpolate_grid(cs%interp_CS, densities, count_nonzero_layers, &
191  htmp, xtmp, cs%target_density, nz, h1, x1)
192 
193  call old_inflate_layers_1d( cs%min_thickness, nz, h1 )
194  x1(1) = 0.0 ; do k = 1,nz ; x1(k+1) = x1(k) + h1(k) ; end do
195 
196  ! Remap T and S from previous grid to new grid
197  do k = 1,nz
198  h1(k) = x1(k+1) - x1(k)
199  end do
200 
201  call remapping_core_h(remapcs, nz, h0, s, nz, h1, tmp)
202  s_tmp(:) = tmp(:)
203 
204  call remapping_core_h(remapcs, nz, h0, t, nz, h1, tmp)
205  t_tmp(:) = tmp(:)
206 
207  ! Compute the deviation between two successive grids
208  deviation = 0.0
209  x0(1) = 0.0
210  x1(1) = 0.0
211  do k = 2,nz
212  x0(k) = x0(k-1) + h0(k-1)
213  x1(k) = x1(k-1) + h1(k-1)
214  deviation = deviation + (x0(k)-x1(k))**2
215  end do
216  deviation = sqrt( deviation / (nz-1) )
217 
218  m = m + 1
219 
220  ! Copy final grid onto start grid for next iteration
221  h0(:) = h1(:)
222 
223  end do ! end regridding iterations
224 
225  if (cs%integrate_downward_for_e) then
226  zinterface(1) = 0.
227  do k = 1,nz
228  zinterface(k+1) = zinterface(k) - h1(k)
229  ! Adjust interface position to accomodate inflating layers
230  ! without disturbing the interface above
231  enddo
232  else
233  ! The rest of the model defines grids integrating up from the bottom
234  zinterface(nz+1) = -depth
235  do k = nz,1,-1
236  zinterface(k) = zinterface(k+1) + h1(k)
237  ! Adjust interface position to accomodate inflating layers
238  ! without disturbing the interface above
239  enddo
240  endif
241 
242 end subroutine build_rho_column
243 
244 !------------------------------------------------------------------------------
245 ! Inflate vanished layers to finite (nonzero) width
246 !------------------------------------------------------------------------------
247 subroutine old_inflate_layers_1d( minThickness, N, h )
249  ! Argument
250  real, intent(in) :: minThickness
251  integer, intent(in) :: N
252  real, intent(inout) :: h(:)
253 
254  ! Local variable
255  integer :: k
256  integer :: k_found
257  integer :: count_nonzero_layers
258  real :: delta
259  real :: correction
260  real :: maxThickness
261 
262  ! Count number of nonzero layers
263  count_nonzero_layers = 0
264  do k = 1,n
265  if ( h(k) > minthickness ) then
266  count_nonzero_layers = count_nonzero_layers + 1
267  end if
268  end do
269 
270  ! If all layer thicknesses are greater than the threshold, exit routine
271  if ( count_nonzero_layers == n ) return
272 
273  ! If all thicknesses are zero, inflate them all and exit
274  if ( count_nonzero_layers == 0 ) then
275  do k = 1,n
276  h(k) = minthickness
277  end do
278  return
279  end if
280 
281  ! Inflate zero layers
282  correction = 0.0
283  do k = 1,n
284  if ( h(k) <= minthickness ) then
285  delta = minthickness - h(k)
286  correction = correction + delta
287  h(k) = h(k) + delta
288  end if
289  end do
290 
291  ! Modify thicknesses of nonzero layers to ensure volume conservation
292  maxthickness = h(1)
293  k_found = 1
294  do k = 1,n
295  if ( h(k) > maxthickness ) then
296  maxthickness = h(k)
297  k_found = k
298  end if
299  end do
300 
301  h(k_found) = h(k_found) - correction
302 
303 end subroutine old_inflate_layers_1d
304 
305 end module coord_rho
Control structure containing required parameters for the rho coordinate.
Definition: coord_rho.F90:12
subroutine, public old_inflate_layers_1d(minThickness, N, h)
Definition: coord_rho.F90:248
Calculates density of sea water from T, S and P.
Definition: MOM_EOS.F90:45
Provides column-wise vertical remapping functions.
subroutine, public end_coord_rho(CS)
Definition: coord_rho.F90:64
subroutine, public set_rho_params(CS, min_thickness, integrate_downward_for_e, interp_CS)
Definition: coord_rho.F90:73
subroutine, public build_and_interpolate_grid(CS, densities, n0, h0, x0, target_values, n1, h1, x1)
Container for remapping parameters.
subroutine, public build_rho_column(CS, remapCS, nz, depth, h, T, S, eqn_of_state, zInterface)
Definition: coord_rho.F90:86
integer, parameter nb_regridding_iterations
Maximum number of regridding iterations.
Definition: coord_rho.F90:36
Provides subroutines for quantities specific to the equation of state.
Definition: MOM_EOS.F90:2
subroutine, public remapping_core_h(CS, n0, h0, u0, n1, h1, u1)
Remaps column of values u0 on grid h0 to grid h1 assuming the top edge is aligned.
Regrid columns for the continuous isopycnal (rho) coordinate.
Definition: coord_rho.F90:2
integer, parameter, public degree_max
subroutine, public mom_error(level, message, all_print)
subroutine, public init_coord_rho(CS, nk, ref_pressure, target_density, interp_CS)
Initialise a rho_CS with pointers to parameters.
Definition: coord_rho.F90:47
A control structure for the equation of state.
Definition: MOM_EOS.F90:55
real, parameter deviation_tolerance
Deviation tolerance between succesive grids in regridding iterations.
Definition: coord_rho.F90:38