MOM6
coord_adapt Module Reference

Detailed Description

Regrid columns for the adaptive coordinate.

Data Types

type  adapt_cs
 

Functions/Subroutines

subroutine, public init_coord_adapt (CS, nk, coordinateResolution)
 Initialise an adapt_CS with parameters. More...
 
subroutine, public end_coord_adapt (CS)
 Clean up the coordinate control structure. More...
 
subroutine, public set_adapt_params (CS, adaptTimeRatio, adaptAlpha, adaptZoom, adaptZoomCoeff, adaptBuoyCoeff, adaptDrho0, adaptDoMin)
 
subroutine, public build_adapt_column (CS, G, GV, tv, i, j, zInt, tInt, sInt, h, zNext)
 

Function/Subroutine Documentation

◆ build_adapt_column()

subroutine, public coord_adapt::build_adapt_column ( type(adapt_cs), intent(in)  CS,
type(ocean_grid_type), intent(in)  G,
type(verticalgrid_type), intent(in)  GV,
type(thermo_var_ptrs), intent(in)  tv,
integer, intent(in)  i,
integer, intent(in)  j,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke+1), intent(in)  zInt,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke+1), intent(in)  tInt,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke+1), intent(in)  sInt,
real, dimension( g %isd: g %ied, g %jsd: g %jed, gv %ke), intent(in)  h,
real, dimension( gv %ke+1), intent(inout)  zNext 
)
Parameters
[in]gThe ocean's grid structure
[in]gvThe ocean's vertical grid structure
[in]tvA structure pointing to various thermodynamic variables
[in]hLayer thicknesses, in H (usually m or kg m-2)

Definition at line 92 of file coord_adapt.F90.

References mom_eos::calculate_density_derivs().

92  type(adapt_cs), intent(in) :: cs
93  type(ocean_grid_type), intent(in) :: g !< The ocean's grid structure
94  type(verticalgrid_type), intent(in) :: gv !< The ocean's vertical grid structure
95  type(thermo_var_ptrs), intent(in) :: tv !< A structure pointing to various thermodynamic variables
96  integer, intent(in) :: i, j
97  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)+1), intent(in) :: zint, tint, sint
98  real, dimension(SZI_(G),SZJ_(G),SZK_(GV)), intent(in) :: h !< Layer thicknesses, in H (usually m or kg m-2)
99  real, dimension(SZK_(GV)+1), intent(inout) :: znext ! updated interface positions
100 
101  ! Local variables
102  integer :: k, nz
103  real :: h_up, b1, b_denom_1, d1, depth, drdz, nominal_z, stretching
104  real, dimension(SZK_(GV)+1) :: alpha, beta, del2sigma ! drho/dT and drho/dS
105  real, dimension(SZK_(GV)) :: kgrid, c1 ! grid diffusivity on layers, and tridiagonal work array
106 
107  nz = cs%nk
108 
109  ! set bottom and surface of zNext
110  znext(1) = 0.
111  znext(nz+1) = zint(i,j,nz+1)
112 
113  ! local depth for scaling diffusivity
114  depth = g%bathyT(i,j) * gv%m_to_H
115 
116  ! initialize del2sigma to zero
117  del2sigma(:) = 0.
118 
119  ! calculate del-squared of neutral density by a
120  ! stencilled finite difference
121  ! TODO: this needs to be adjusted to account for vanished layers near topography
122 
123  ! up (j-1)
124  if (g%mask2dT(i,j-1) > 0.) then
125  call calculate_density_derivs( &
126  0.5 * (tint(i,j,2:nz) + tint(i,j-1,2:nz)), &
127  0.5 * (sint(i,j,2:nz) + sint(i,j-1,2:nz)), &
128  0.5 * (zint(i,j,2:nz) + zint(i,j-1,2:nz)) * gv%H_to_Pa, &
129  alpha, beta, 2, nz - 1, tv%eqn_of_state)
130 
131  del2sigma(2:nz) = del2sigma(2:nz) + &
132  (alpha(2:nz) * (tint(i,j-1,2:nz) - tint(i,j,2:nz)) + &
133  beta(2:nz) * (sint(i,j-1,2:nz) - sint(i,j,2:nz)))
134  endif
135  ! down (j+1)
136  if (g%mask2dT(i,j+1) > 0.) then
137  call calculate_density_derivs( &
138  0.5 * (tint(i,j,2:nz) + tint(i,j+1,2:nz)), &
139  0.5 * (sint(i,j,2:nz) + sint(i,j+1,2:nz)), &
140  0.5 * (zint(i,j,2:nz) + zint(i,j+1,2:nz)) * gv%H_to_Pa, &
141  alpha, beta, 2, nz - 1, tv%eqn_of_state)
142 
143  del2sigma(2:nz) = del2sigma(2:nz) + &
144  (alpha(2:nz) * (tint(i,j+1,2:nz) - tint(i,j,2:nz)) + &
145  beta(2:nz) * (sint(i,j+1,2:nz) - sint(i,j,2:nz)))
146  endif
147  ! left (i-1)
148  if (g%mask2dT(i-1,j) > 0.) then
149  call calculate_density_derivs( &
150  0.5 * (tint(i,j,2:nz) + tint(i-1,j,2:nz)), &
151  0.5 * (sint(i,j,2:nz) + sint(i-1,j,2:nz)), &
152  0.5 * (zint(i,j,2:nz) + zint(i-1,j,2:nz)) * gv%H_to_Pa, &
153  alpha, beta, 2, nz - 1, tv%eqn_of_state)
154 
155  del2sigma(2:nz) = del2sigma(2:nz) + &
156  (alpha(2:nz) * (tint(i-1,j,2:nz) - tint(i,j,2:nz)) + &
157  beta(2:nz) * (sint(i-1,j,2:nz) - sint(i,j,2:nz)))
158  endif
159  ! right (i+1)
160  if (g%mask2dT(i+1,j) > 0.) then
161  call calculate_density_derivs( &
162  0.5 * (tint(i,j,2:nz) + tint(i+1,j,2:nz)), &
163  0.5 * (sint(i,j,2:nz) + sint(i+1,j,2:nz)), &
164  0.5 * (zint(i,j,2:nz) + zint(i+1,j,2:nz)) * gv%H_to_Pa, &
165  alpha, beta, 2, nz - 1, tv%eqn_of_state)
166 
167  del2sigma(2:nz) = del2sigma(2:nz) + &
168  (alpha(2:nz) * (tint(i+1,j,2:nz) - tint(i,j,2:nz)) + &
169  beta(2:nz) * (sint(i+1,j,2:nz) - sint(i,j,2:nz)))
170  endif
171 
172  ! at this point, del2sigma contains the local neutral density curvature at
173  ! h-points, on interfaces
174  ! we need to divide by drho/dz to give an interfacial displacement
175  !
176  ! a positive curvature means we're too light relative to adjacent columns,
177  ! so del2sigma needs to be positive too (push the interface deeper)
178  call calculate_density_derivs(tint(i,j,:), sint(i,j,:), zint(i,j,:) * gv%H_to_Pa, &
179  alpha, beta, 1, nz + 1, tv%eqn_of_state)
180  do k = 2, nz
181  ! TODO make lower bound here configurable
182  del2sigma(k) = del2sigma(k) * (0.5 * (h(i,j,k-1) + h(i,j,k))) / &
183  max(alpha(k) * (tv%T(i,j,k) - tv%T(i,j,k-1)) + &
184  beta(k) * (tv%S(i,j,k) - tv%S(i,j,k-1)), 1e-20)
185 
186  ! don't move the interface so far that it would tangle with another
187  ! interface in the direction we're moving (or exceed a Nyquist limit
188  ! that could cause oscillations of the interface)
189  h_up = merge(h(i,j,k), h(i,j,k-1), del2sigma(k) > 0.)
190  del2sigma(k) = 0.5 * cs%adaptAlpha * &
191  sign(min(abs(del2sigma(k)), 0.5 * h_up), del2sigma(k))
192 
193  ! update interface positions so we can diffuse them
194  znext(k) = zint(i,j,k) + del2sigma(k)
195  enddo
196 
197  ! solve diffusivity equation to smooth grid
198  ! upper diagonal coefficients: -kGrid(2:nz)
199  ! lower diagonal coefficients: -kGrid(1:nz-1)
200  ! diagonal coefficients: 1 + (kGrid(1:nz-1) + kGrid(2:nz))
201  !
202  ! first, calculate the diffusivities within layers
203  do k = 1, nz
204  ! calculate the dr bit of drdz
205  drdz = 0.5 * (alpha(k) + alpha(k+1)) * (tint(i,j,k+1) - tint(i,j,k)) + &
206  0.5 * (beta(k) + beta(k+1)) * (sint(i,j,k+1) - sint(i,j,k))
207  ! divide by dz from the new interface positions
208  drdz = drdz / (znext(k) - znext(k+1) + gv%H_subroundoff)
209  ! don't do weird stuff in unstably-stratified regions
210  drdz = max(drdz, 0.)
211 
212  ! set vertical grid diffusivity
213  kgrid(k) = (cs%adaptTimeRatio * nz**2 * depth) * &
214  (cs%adaptZoomCoeff / (cs%adaptZoom * gv%m_to_H + 0.5*(znext(k) + znext(k+1))) + &
215  (cs%adaptBuoyCoeff * drdz / cs%adaptDrho0) + &
216  max(1.0 - cs%adaptZoomCoeff - cs%adaptBuoyCoeff, 0.0) / depth)
217  enddo
218 
219  ! initial denominator (first diagonal element)
220  b1 = 1.0
221  ! initial Q_1 = 1 - q_1 = 1 - 0/1
222  d1 = 1.0
223  ! work on all interior interfaces
224  do k = 2, nz
225  ! calculate numerator of Q_k
226  b_denom_1 = 1. + d1 * kgrid(k-1)
227  ! update denominator for k
228  b1 = 1.0 / (b_denom_1 + kgrid(k))
229 
230  ! calculate q_k
231  c1(k) = kgrid(k) * b1
232  ! update Q_k = 1 - q_k
233  d1 = b_denom_1 * b1
234 
235  ! update RHS
236  znext(k) = b1 * (znext(k) + kgrid(k-1)*znext(k-1))
237  enddo
238  ! final substitution
239  do k = nz, 2, -1
240  znext(k) = znext(k) + c1(k)*znext(k+1)
241  enddo
242 
243  if (cs%adaptDoMin) then
244  nominal_z = 0.
245  stretching = zint(i,j,nz+1) / depth
246 
247  do k = 2, nz+1
248  nominal_z = nominal_z + cs%coordinateResolution(k-1) * stretching
249  ! take the deeper of the calculated and nominal positions
250  znext(k) = max(znext(k), nominal_z)
251  ! interface can't go below topography
252  znext(k) = min(znext(k), zint(i,j,nz+1))
253  enddo
254  endif
Here is the call graph for this function:

◆ end_coord_adapt()

subroutine, public coord_adapt::end_coord_adapt ( type(adapt_cs), pointer  CS)

Clean up the coordinate control structure.

Definition at line 65 of file coord_adapt.F90.

Referenced by mom_regridding::end_regridding().

65  type(adapt_cs), pointer :: cs
66 
67  ! nothing to do
68  if (.not. associated(cs)) return
69  deallocate(cs%coordinateResolution)
70  deallocate(cs)
Here is the caller graph for this function:

◆ init_coord_adapt()

subroutine, public coord_adapt::init_coord_adapt ( type(adapt_cs), pointer  CS,
integer, intent(in)  nk,
real, dimension(:), intent(in)  coordinateResolution 
)

Initialise an adapt_CS with parameters.

Parameters
csUnassociated pointer to hold the control structure

Definition at line 51 of file coord_adapt.F90.

References mom_error_handler::mom_error().

51  type(adapt_cs), pointer :: cs !< Unassociated pointer to hold the control structure
52  integer, intent(in) :: nk
53  real, dimension(:), intent(in) :: coordinateresolution
54 
55  if (associated(cs)) call mom_error(fatal, "init_coord_adapt: CS already associated")
56  allocate(cs)
57  allocate(cs%coordinateResolution(nk))
58 
59  cs%nk = nk
60  cs%coordinateResolution(:) = coordinateresolution(:)
Here is the call graph for this function:

◆ set_adapt_params()

subroutine, public coord_adapt::set_adapt_params ( type(adapt_cs), pointer  CS,
real, intent(in), optional  adaptTimeRatio,
real, intent(in), optional  adaptAlpha,
real, intent(in), optional  adaptZoom,
real, intent(in), optional  adaptZoomCoeff,
real, intent(in), optional  adaptBuoyCoeff,
real, intent(in), optional  adaptDrho0,
logical, intent(in), optional  adaptDoMin 
)

Definition at line 75 of file coord_adapt.F90.

References mom_error_handler::mom_error().

75  type(adapt_cs), pointer :: cs
76  real, optional, intent(in) :: adapttimeratio, adaptalpha, adaptzoom, adaptzoomcoeff
77  real, optional, intent(in) :: adaptbuoycoeff, adaptdrho0
78  logical, optional, intent(in) :: adaptdomin
79 
80  if (.not. associated(cs)) call mom_error(fatal, "set_adapt_params: CS not associated")
81 
82  if (present(adapttimeratio)) cs%adaptTimeRatio = adapttimeratio
83  if (present(adaptalpha)) cs%adaptAlpha = adaptalpha
84  if (present(adaptzoom)) cs%adaptZoom = adaptzoom
85  if (present(adaptzoomcoeff)) cs%adaptZoomCoeff = adaptzoomcoeff
86  if (present(adaptbuoycoeff)) cs%adaptBuoyCoeff = adaptbuoycoeff
87  if (present(adaptdrho0)) cs%adaptDrho0 = adaptdrho0
88  if (present(adaptdomin)) cs%adaptDoMin = adaptdomin
Here is the call graph for this function: