@@ -247,6 +247,8 @@ subroutine compute_frontogenesis(frontgf,frontga,tl,tlq,elem,ederiv,hybrid,nets,
247247 ! Integrated into gravity_waves_sources module, several arguments made global
248248 ! to prevent repeated allocation/initialization
249249 !
250+ ! Frontogenesis function correction by Walter Hannah, Mark Taylor, and Jack Chen. October 2025
251+ !
250252 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
251253 use physconst, only: cappa
252254 use air_composition,only: dry_air_species_num, thermodynamic_active_species_num
@@ -273,14 +275,46 @@ subroutine compute_frontogenesis(frontgf,frontga,tl,tlq,elem,ederiv,hybrid,nets,
273275 real (r8 ) :: frontga_gll(np,np,nlev,nets:nete)
274276 integer :: k,kptr,i,j,ie,component,h,nq,m_cnst
275277 real (r8 ) :: gradth(np,np,2 ,nlev,nets:nete) ! grad(theta)
276- real (r8 ) :: p(np,np) ! pressure at mid points
277- real (r8 ) :: pint(np,np) ! pressure at interface points
278- real (r8 ) :: theta(np,np) ! potential temperature at mid points
278+
279+ real (r8 ) :: p(np,np,nlev) ! pressure at mid points
280+ real (r8 ) :: pint(np,np,nlev+1 ) ! pressure at interface points
281+ real (r8 ) :: gradp(np,np,2 ) ! grad(pressure)
282+ real (r8 ) :: theta(np,np,nlev) ! potential temperature at mid points
283+ real (r8 ) :: dtheta_dp(np,np,nlev) ! d(theta)/dp for eta to pressure surface correction
284+ real (r8 ) :: dum_grad(np,np,2 ) ! ?
285+ real (r8 ) :: dum_cart(np,np,3 ,nlev) ! d/dp of ?
286+ real (r8 ) :: ddp_dum_cart(np,np,3 ,nlev) ! ?
279287 real (r8 ) :: C(np,np,2 ), sum_water(np,np)
280288
289+ ! By Mark Taylor
290+ ! For a vector velocity "v", a tensor "grad(v)", and a vector "grad(theta)",
291+ ! this loop computes the vector "grad(theta)*grad(v)"
292+ !
293+ ! Representing the tensor "grad(v)" in spherical coordinates is difficult. This routine
294+ ! avoids this by computing a mathematically equivalent form using a mixture of
295+ ! Cartesian and spherical coordinates
296+ !
297+ ! This routine is a modified version of derivative_mod.F90:ugradv_sphere() in that the
298+ ! grad(v) term is modified to compute grad_p(v) - the gradient on p-surfaces expressed
299+ ! in terms of the gradient on model surfaces and a vertical pressure gradient.
300+ !
301+ ! First, v is represented in cartesian coordinates v(c) for c=1,2,3
302+ ! For each v(c), we compute its gradient on p-surfaces via:
303+ ! grad(v(c)) - d(v(c))/dz grad(p)
304+ ! Each of these gradients is represented in *spherical* coordinates (i=1,2)
305+ !
306+ ! We then dot each of these vectors with grad(theta). This dot product is computed
307+ ! in spherical coordinates. The end result is dum_cart(c), for c=1,2,3
308+ ! These three scalars are the three Cartesian coefficients of
309+ ! the vector "grad(theta)*grad(v)"
310+ !
311+ ! This Cartesian vector is then transformed back to spherical coordinates
312+ !
313+
281314 do ie= nets,nete
282315 ! pressure at model top
283- pint(:,:) = hvcoord% hyai(1 )* hvcoord% ps0
316+ pint(:,:,1 ) = hvcoord% hyai(1 )* hvcoord% ps0
317+
284318 do k= 1 ,nlev
285319 ! moist pressure at mid points
286320 sum_water(:,:) = 1.0_r8
@@ -291,15 +325,49 @@ subroutine compute_frontogenesis(frontgf,frontga,tl,tlq,elem,ederiv,hybrid,nets,
291325 !
292326 sum_water(:,:) = sum_water(:,:) + elem(ie)% state% Qdp(:,:,k,m_cnst,tlq)/ elem(ie)% state% dp3d(:,:,k,tl)
293327 end do
294- p(:,:) = pint(:,:) + 0.5_r8 * sum_water(:,:)* elem(ie)% state% dp3d(:,:,k,tl)
328+ p(:,:,k ) = pint(:,:,k ) + 0.5_r8 * sum_water(:,:)* elem(ie)% state% dp3d(:,:,k,tl)
295329 ! moist pressure at interface for next iteration
296- pint(:,:) = pint(:,:)+ elem(ie)% state% dp3d(:,:,k,tl)
330+ pint(:,:,k +1 ) = pint(:,:,k )+ elem(ie)% state% dp3d(:,:,k,tl)
297331 !
298- theta(:,:) = elem(ie)% state% T(:,:,k,tl)* (psurf_ref / p(:,:))** cappa
299- ! gradth(:,:,:,k,ie) = gradient_sphere(theta,ederiv,elem(ie)%Dinv)
300- call gradient_sphere(theta,ederiv,elem(ie)% Dinv,gradth(:,:,:,k,ie))
301- ! compute C = (grad(theta) dot grad ) u
302- C(:,:,:) = ugradv_sphere(gradth(:,:,:,k,ie), elem(ie)% state% v(:,:,:,k,tl),ederiv,elem(ie))
332+ theta(:,:,k) = elem(ie)% state% T(:,:,k,tl)* (psurf_ref / p(:,:,k))** cappa
333+ end do
334+
335+ call compute_vertical_derivative(pint,p,theta,dtheta_dp)
336+
337+ do k= 1 ,nlev
338+ call gradient_sphere(theta(:,:,k),ederiv,elem(ie)% Dinv,gradth(:,:,:,k,ie))
339+
340+ call gradient_sphere(p(:,:,k),ederiv,elem(ie)% Dinv,gradp)
341+
342+ do component= 1 ,2
343+ gradth(:,:,component,k,ie) = gradth(:,:,component,k,ie) - dtheta_dp(:,:,k) * gradp(:,:,component)
344+ end do
345+ end do
346+
347+ do k= 1 ,nlev
348+ do component= 1 ,3
349+ dum_cart(:,:,component,k) = sum ( elem(ie)% vec_sphere2cart(:,:,component,:) * elem(ie)% state% v(:,:,:,k,tl),3 )
350+ end do
351+ end do
352+
353+ do component= 1 ,3
354+ call compute_vertical_derivative(pint,p,dum_cart(:,:,component,:),ddp_dum_cart(:,:,component,:))
355+ end do
356+ do k= 1 ,nlev
357+ call gradient_sphere(p(:,:,k),ederiv,elem(ie)% Dinv,gradp)
358+
359+ do component= 1 ,3
360+ call gradient_sphere(dum_cart(:,:,component,k),ederiv,elem(ie)% Dinv,dum_grad)
361+ do i= 1 ,2
362+ dum_grad(:,:,i) = dum_grad(:,:,i) - ddp_dum_cart(:,:,component,k) * gradp(:,:,i)
363+ end do
364+ dum_cart(:,:,component,k) = sum ( gradth(:,:,:,k,ie) * dum_grad , 3 )
365+ end do
366+
367+ do i= 1 ,2
368+ C(:,:,i) = sum (dum_cart(:,:,:,k)* elem(ie)% vec_sphere2cart(:,:,:,i), 3 )
369+ end do
370+
303371 ! gradth dot C
304372 frontgf_gll(:,:,k,ie) = - ( C(:,:,1 )* gradth(:,:,1 ,k,ie) + C(:,:,2 )* gradth(:,:,2 ,k,ie) )
305373 ! apply mass matrix
@@ -351,5 +419,38 @@ subroutine compute_frontogenesis(frontgf,frontga,tl,tlq,elem,ederiv,hybrid,nets,
351419 enddo
352420 end subroutine compute_frontogenesis
353421
422+ subroutine compute_vertical_derivative (pint ,pmid ,data ,ddata_dp )
423+ !- --------------------------------------------------------------------------
424+ real (r8 ), intent (in ) :: pint(np,np,nlev+1 )
425+ real (r8 ), intent (in ) :: pmid(np,np,nlev)
426+ real (r8 ), intent (in ) :: data (np,np,nlev)
427+ real (r8 ), intent (out ) :: ddata_dp(np,np,nlev)
428+ !- --------------------------------------------------------------------------
429+ integer :: k
430+ real (r8 ) :: pint_above(np,np) ! pressure interpolated to interface above the current k mid-point
431+ real (r8 ) :: pint_below(np,np) ! pressure interpolated to interface below the current k mid-point
432+ real (r8 ) :: dint_above(np,np) ! data interpolated to interface above the current k mid-point
433+ real (r8 ) :: dint_below(np,np) ! data interpolated to interface below the current k mid-point
434+ !- --------------------------------------------------------------------------
435+ do k = 1 ,nlev
436+ if (k== 1 ) then
437+ pint_above = pmid(:,:,k)
438+ pint_below = pint(:,:,k+1 )
439+ dint_above = data (:,:,k)
440+ dint_below = ( data (:,:,k+1 ) + data (:,:,k) ) / 2.0_r8
441+ elseif (k== nlev) then
442+ pint_above = pint(:,:,k)
443+ pint_below = pmid(:,:,k)
444+ dint_above = ( data (:,:,k-1 ) + data (:,:,k) ) / 2.0_r8
445+ dint_below = data (:,:,k)
446+ else
447+ pint_above = pint(:,:,k)
448+ pint_below = pint(:,:,k+1 )
449+ dint_above = ( data (:,:,k-1 ) + data (:,:,k) ) / 2.0_r8
450+ dint_below = ( data (:,:,k+1 ) + data (:,:,k) ) / 2.0_r8
451+ end if
452+ ddata_dp(:,:,k) = ( dint_above - dint_below ) / ( pint_above - pint_below )
453+ end do
454+ end subroutine compute_vertical_derivative
354455
355456end module gravity_waves_sources
0 commit comments