diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d4023ec3f..0cc9802f8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,8 +6,6 @@ and this project uses `yyyy.rr[.pp]`, where `yyyy` is the year a patch is releas `rr` is a sequential release number (starting from `01`), and an optional two-digit sequential patch number (starting from `01`). -<<<<<<< HEAD -======= ## [2023.01.01] - 2023-06-06 ### Changed - FMS2_IO: Performance changes for domain_reads_2d and domain_reads_3d: @@ -23,7 +21,6 @@ sequential patch number (starting from `01`). - FMS2_IO: Extended mpp_scatter and mpp_gather to work for int8; added a kludge for scatter since the data is assumed to be (x,y,z) ->>>>>>> origin/mixedmode_base ## [2023.01] - 2023-04-03 ### Known Issues - If using GCC 10 or higher as well as MPICH, compilation errors will occur unless `-fallow-argument-mismatch` is included in the Fortran compiler flags(the flag will now be added automatically if building with autotools or CMake). diff --git a/CMakeLists.txt b/CMakeLists.txt index 5571cbf28c..7646e3bf1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -304,6 +304,7 @@ foreach(kind ${kinds}) fms2_io/include string_utils/include mpp/include + monin_obukhov/include sat_vapor_pres/include horiz_interp/include random_numbers/include @@ -349,6 +350,7 @@ foreach(kind ${kinds}) $ $ $ + $ $ $ $ @@ -359,6 +361,7 @@ foreach(kind ${kinds}) $ $) + target_include_directories(${libTgt} INTERFACE $ $) diff --git a/axis_utils/include/axis_utils2.inc b/axis_utils/include/axis_utils2.inc index 3535e70df7..83088e7b85 100644 --- a/axis_utils/include/axis_utils2.inc +++ b/axis_utils/include/axis_utils2.inc @@ -177,14 +177,11 @@ !! lon = 0 1 2 3 4 5 ... 358 359; lon_strt = 3 !! ==> lon = 3 4 5 6 7 8 ... 359 360 361 362; istrt = 4 !! - !! lon = 0 1 2 3 4 5 ... 358 359; lon_strt = 0 - !! ==> lon = 0 1 2 3 4 5 ... 358 359; istrt = 0 subroutine TRANLON_(lon, lon_start, istrt) real(kind=FMS_AU_KIND_), intent(inout), dimension(:) :: lon real(kind=FMS_AU_KIND_), intent(in) :: lon_start integer, intent(out) :: istrt - integer :: len, i real(kind=FMS_AU_KIND_) :: lon_strt, tmp(size(lon(:))-1) diff --git a/monin_obukhov/Makefile.am b/monin_obukhov/Makefile.am index 6b3759b55f..9af5e90e95 100644 --- a/monin_obukhov/Makefile.am +++ b/monin_obukhov/Makefile.am @@ -22,24 +22,39 @@ # Ed Hartnett 2/22/19 -AM_CPPFLAGS = -I$(top_srcdir)/include +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/monin_obukhov/include AM_FCFLAGS = $(FC_MODINC). $(FC_MODOUT)$(MODDIR) noinst_LTLIBRARIES = libmonin_obukhov.la libmonin_obukhov_la_SOURCES = \ - monin_obukhov.F90 \ - monin_obukhov_inter.F90 - -monin_obukhov_mod.$(FC_MODEXT): monin_obukhov_inter.$(FC_MODEXT) + monin_obukhov.F90 \ + monin_obukhov_inter.F90 \ + include/monin_obukhov_r4.fh \ + include/monin_obukhov_r8.fh \ + include/monin_obukhov.inc \ + include/monin_obukhov_inter_r4.fh \ + include/monin_obukhov_inter_r8.fh \ + include/monin_obukhov_inter.inc + +monin_obukhov_inter.$(FC_MODEXT): \ + include/monin_obukhov_inter_r4.fh \ + include/monin_obukhov_inter_r8.fh \ + include/monin_obukhov_inter.inc + +monin_obukhov_mod.$(FC_MODEXT): \ + monin_obukhov_inter.$(FC_MODEXT) \ + include/monin_obukhov_r4.fh \ + include/monin_obukhov_r8.fh \ + include/monin_obukhov.inc # Mod files are built and then installed as headers. MODFILES = \ - monin_obukhov_inter.$(FC_MODEXT) \ - monin_obukhov_mod.$(FC_MODEXT) + monin_obukhov_mod.$(FC_MODEXT) \ + monin_obukhov_inter.$(FC_MODEXT) nodist_include_HEADERS = $(MODFILES) BUILT_SOURCES = $(MODFILES) EXTRA_DIST = monin_obukhov.tech.ps -include $(top_srcdir)/mkmods.mk +include $(top_srcdir)/mkmods.mk \ No newline at end of file diff --git a/monin_obukhov/include/monin_obukhov.inc b/monin_obukhov/include/monin_obukhov.inc index ac8a89075f..e69294fe48 100644 --- a/monin_obukhov/include/monin_obukhov.inc +++ b/monin_obukhov/include/monin_obukhov.inc @@ -16,188 +16,24 @@ !* You should have received a copy of the GNU Lesser General Public !* License along with FMS. If not, see . !*********************************************************************** -!> @defgroup monin_obukhov_mod monin_obukhov_mod -!> @ingroup monin_obukhov -!> @brief Routines for computing surface drag coefficients -!! from data at the lowest model level -!! and for computing the profile of fields -!! between the lowest model level and the ground -!! using Monin-Obukhov scaling - -module monin_obukhov_mod - -use constants_mod, only: grav, vonkarm -use mpp_mod, only: input_nml_file -use fms_mod, only: error_mesg, FATAL, check_nml_error, & - mpp_pe, mpp_root_pe, stdlog, & - write_version_number -use monin_obukhov_inter, only: monin_obukhov_diff, monin_obukhov_drag_1d, & - monin_obukhov_profile_1d, monin_obukhov_stable_mix -implicit none -private -!======================================================================= - public :: monin_obukhov_init - public :: monin_obukhov_end - public :: mo_drag - public :: mo_profile - public :: mo_diff - public :: stable_mix -!======================================================================= - -!> @brief Compute surface drag coefficients -!> @ingroup monin_obukhov_mod -interface mo_drag - module procedure mo_drag_0d, mo_drag_1d, mo_drag_2d -end interface - - -!> @ingroup monin_obukhov_mod -interface mo_profile - module procedure mo_profile_0d, mo_profile_1d, mo_profile_2d, & - mo_profile_0d_n, mo_profile_1d_n, mo_profile_2d_n -end interface - -!> @ingroup monin_obukhov_mod -interface mo_diff - module procedure mo_diff_0d_n, mo_diff_0d_1, & - mo_diff_1d_n, mo_diff_1d_1, & - mo_diff_2d_n, mo_diff_2d_1 -end interface - -!> @ingroup monin_obukhov_mod -interface stable_mix - module procedure stable_mix_0d, stable_mix_1d, & - stable_mix_2d, stable_mix_3d -end interface - -!> @addtogroup monin_obukhov_mod -!> @{ - -!----------------------------------------------------------------------- -! version number of this module -! Include variable "version" to be written to log file. -#include - -!======================================================================= - -! DEFAULT VALUES OF NAMELIST PARAMETERS: - -real :: rich_crit = 2.0 -real :: drag_min_heat = 1.e-05 -real :: drag_min_moist = 1.e-05 -real :: drag_min_mom = 1.e-05 -logical :: neutral = .false. -integer :: stable_option = 1 -real :: zeta_trans = 0.5 -logical :: new_mo_option = .false. - - -namelist /monin_obukhov_nml/ rich_crit, neutral, drag_min_heat, & - drag_min_moist, drag_min_mom, & - stable_option, zeta_trans, new_mo_option !miz - -!======================================================================= - -! MODULE VARIABLES - -real, parameter :: small = 1.e-04 -real :: b_stab, r_crit, lambda, rich_trans -real :: sqrt_drag_min_heat, sqrt_drag_min_moist, sqrt_drag_min_mom -logical :: module_is_initialized = .false. - - -contains - -!======================================================================= - -subroutine monin_obukhov_init - -integer :: ierr, io, logunit - -!------------------- read namelist input ------------------------------- - - read (input_nml_file, nml=monin_obukhov_nml, iostat=io) - ierr = check_nml_error(io,"monin_obukhov_nml") - -!---------- output namelist to log------------------------------------- - - if ( mpp_pe() == mpp_root_pe() ) then - call write_version_number('MONIN_OBUKOV_MOD', version) - logunit = stdlog() - write (logunit, nml=monin_obukhov_nml) - endif - -!---------------------------------------------------------------------- -if(rich_crit.le.0.25) call error_mesg( & - 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & - 'rich_crit in monin_obukhov_mod must be > 0.25', FATAL) - -if(drag_min_heat.le.0.0) call error_mesg( & - 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & - 'drag_min_heat in monin_obukhov_mod must be >= 0.0', FATAL) - -if(drag_min_moist.le.0.0) call error_mesg( & - 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & - 'drag_min_moist in monin_obukhov_mod must be >= 0.0', FATAL) - -if(drag_min_mom.le.0.0) call error_mesg( & - 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & - 'drag_min_mom in monin_obukhov_mod must be >= 0.0', FATAL) - -if(stable_option < 1 .or. stable_option > 2) call error_mesg( & - 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & - 'the only allowable values of stable_option are 1 and 2', FATAL) - -if(stable_option == 2 .and. zeta_trans < 0) call error_mesg( & - 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & - 'zeta_trans must be positive', FATAL) - -b_stab = 1.0/rich_crit -r_crit = 0.95*rich_crit ! convergence can get slow if one is - ! close to rich_crit - -sqrt_drag_min_heat = 0.0 -if(drag_min_heat.ne.0.0) sqrt_drag_min_heat = sqrt(drag_min_heat) - -sqrt_drag_min_moist = 0.0 -if(drag_min_moist.ne.0.0) sqrt_drag_min_moist = sqrt(drag_min_moist) - -sqrt_drag_min_mom = 0.0 -if(drag_min_mom.ne.0.0) sqrt_drag_min_mom = sqrt(drag_min_mom) - -lambda = 1.0 + (5.0 - b_stab)*zeta_trans ! used only if stable_option = 2 -rich_trans = zeta_trans/(1.0 + 5.0*zeta_trans) ! used only if stable_option = 2 - -module_is_initialized = .true. - -return -end subroutine monin_obukhov_init - -!======================================================================= - -subroutine monin_obukhov_end - -module_is_initialized = .false. - -end subroutine monin_obukhov_end - -!======================================================================= - -subroutine mo_drag_1d & +subroutine MO_DRAG_1D_ & (pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, drag_q, & u_star, b_star, avail) -real, intent(in) , dimension(:) :: pt, pt0, z, z0, zt, zq, speed -real, intent(inout), dimension(:) :: drag_m, drag_t, drag_q, u_star, b_star -logical, intent(in), optional, dimension(:) :: avail +real(kind=FMS_MO_KIND_), intent(in) , dimension(:) :: pt, pt0, z, z0, zt, zq, speed +real(kind=FMS_MO_KIND_), intent(inout), dimension(:) :: drag_m, drag_t, drag_q, u_star, b_star +logical, intent(in), optional, dimension(:) :: avail -logical :: lavail, avail_dummy(1) -integer :: n, ier +logical :: lavail, avail_dummy(1) +integer :: n, ier -integer, parameter :: max_iter = 20 -real , parameter :: error=1.e-04, zeta_min=1.e-06, small=1.e-04 +integer, parameter :: max_iter = 20 +integer, parameter :: lkind = FMS_MO_KIND_ +real(kind=FMS_MO_KIND_), parameter :: error = 1.0E-04_lkind, & + zeta_min = 1.0E-06_lkind, & + small = 1.0E-04_lkind ! #include "monin_obukhov_interfaces.h" @@ -211,36 +47,36 @@ if(present(avail)) lavail = .true. if(lavail) then if (count(avail) .eq. 0) return - call monin_obukhov_drag_1d(grav, vonkarm, & - & error, zeta_min, max_iter, small, & - & neutral, stable_option, new_mo_option, rich_crit, zeta_trans, &!miz - & drag_min_heat, drag_min_moist, drag_min_mom, & - & n, pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, & - & drag_q, u_star, b_star, lavail, avail, ier) + call monin_obukhov_drag_1d(real(grav, FMS_MO_KIND_), real(vonkarm, FMS_MO_KIND_), & + & error, zeta_min, max_iter, real(small, FMS_MO_KIND_), neutral, stable_option, & + & new_mo_option, real(rich_crit, FMS_MO_KIND_), real(zeta_trans, FMS_MO_KIND_), &!miz + & real(drag_min_heat, FMS_MO_KIND_), real(drag_min_moist, FMS_MO_KIND_), & + & real(drag_min_mom, FMS_MO_KIND_), n, pt, pt0, z, z0, zt, & + & zq, speed, drag_m, drag_t, drag_q, u_star, b_star, lavail, avail, ier) else - call monin_obukhov_drag_1d(grav, vonkarm, & - & error, zeta_min, max_iter, small, & - & neutral, stable_option, new_mo_option, rich_crit, zeta_trans, &!miz - & drag_min_heat, drag_min_moist, drag_min_mom, & - & n, pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, & +call monin_obukhov_drag_1d(real(grav, FMS_MO_KIND_), real(vonkarm, FMS_MO_KIND_), & + & error, zeta_min, max_iter, real(small, FMS_MO_KIND_), neutral, stable_option, & + & new_mo_option, real(rich_crit, FMS_MO_KIND_), real(zeta_trans, FMS_MO_KIND_), &!miz + & real(drag_min_heat, FMS_MO_KIND_), real(drag_min_moist, FMS_MO_KIND_), & + & real(drag_min_mom, FMS_MO_KIND_), n, pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, & & drag_q, u_star, b_star, lavail, avail_dummy, ier) endif -end subroutine mo_drag_1d +end subroutine MO_DRAG_1D_ !======================================================================= -subroutine mo_profile_1d(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & +subroutine MO_PROFILE_1D_(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & del_m, del_t, del_q, avail) -real, intent(in) :: zref, zref_t -real, intent(in) , dimension(:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:) :: del_m, del_t, del_q -logical, intent(in) , optional, dimension(:) :: avail +real(kind=FMS_MO_KIND_), intent(in) :: zref, zref_t +real(kind=FMS_MO_KIND_), intent(in) , dimension(:) :: z, z0, zt, zq, u_star, b_star, q_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: del_m, del_t, del_q +logical, intent(in) , optional, dimension(:) :: avail -logical :: dummy_avail(1) -integer :: n, ier +logical :: dummy_avail(1) +integer :: n, ier ! #include "monin_obukhov_interfaces.h" @@ -252,28 +88,28 @@ if(present(avail)) then if (count(avail) .eq. 0) return - call monin_obukhov_profile_1d(vonkarm, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, & - & n, zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - & del_m, del_t, del_q, .true., avail, ier) + call monin_obukhov_profile_1d(real(vonkarm, FMS_MO_KIND_), & + & neutral, stable_option, new_mo_option, real(rich_crit, FMS_MO_KIND_), & + & real(zeta_trans, FMS_MO_KIND_), n, zref, zref_t, z, z0, zt, zq, u_star, & + & b_star, q_star, del_m, del_t, del_q, .true., avail, ier) else - call monin_obukhov_profile_1d(vonkarm, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, & - & n, zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - & del_m, del_t, del_q, .false., dummy_avail, ier) + call monin_obukhov_profile_1d(real(vonkarm, FMS_MO_KIND_), & + & neutral, stable_option, new_mo_option, real(rich_crit, FMS_MO_KIND_), & + & real(zeta_trans, FMS_MO_KIND_), n, zref, zref_t, z, z0, zt, zq, u_star, & + & b_star, q_star, del_m, del_t, del_q, .false., dummy_avail, ier) endif -end subroutine mo_profile_1d +end subroutine MO_PROFILE_1D_ !======================================================================= -subroutine stable_mix_3d(rich, mix) +subroutine STABLE_MIX_3D_(rich, mix) -real, intent(in) , dimension(:,:,:) :: rich -real, intent(out), dimension(:,:,:) :: mix +real(kind=FMS_MO_KIND_), intent(in) , dimension(:,:,:) :: rich +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:,:) :: mix integer :: n2 !< Size of dimension 2 of mix and rich integer :: n3 !< Size of dimension 3 of mix and rich integer :: i, j !< Loop indices @@ -287,65 +123,67 @@ do j=1, n3 enddo enddo -end subroutine stable_mix_3d + + +end subroutine STABLE_MIX_3D_ !======================================================================= -subroutine mo_diff_2d_n(z, u_star, b_star, k_m, k_h) +subroutine MO_DIFF_2D_N_(z, u_star, b_star, k_m, k_h) -real, intent(in), dimension(:,:,:) :: z -real, intent(in), dimension(:,:) :: u_star, b_star -real, intent(out), dimension(:,:,:) :: k_m, k_h +real(kind=FMS_MO_KIND_), intent(in), dimension(:,:,:) :: z +real(kind=FMS_MO_KIND_), intent(in), dimension(:,:) :: u_star, b_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:,:) :: k_m, k_h -integer :: ni, nj, nk, ier -real, parameter :: ustar_min = 1.e-10 +integer :: ni, nj, nk, ier +integer, parameter :: lkind = FMS_MO_KIND_ +real(kind=FMS_MO_KIND_), parameter :: ustar_min = 1.0E-10_lkind if(.not.module_is_initialized) call error_mesg('mo_diff_2d_n in monin_obukhov_mod', & 'monin_obukhov_init has not been called', FATAL) ni = size(z, 1); nj = size(z, 2); nk = size(z, 3) -call monin_obukhov_diff(vonkarm, & - & ustar_min, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, & - & ni, nj, nk, z, u_star, b_star, k_m, k_h, ier) +call monin_obukhov_diff(real(vonkarm, FMS_MO_KIND_), ustar_min, neutral, & + & stable_option, new_mo_option, real(rich_crit, FMS_MO_KIND_), & + & real(zeta_trans, FMS_MO_KIND_), ni, nj, nk, z, u_star, b_star, & + & k_m, k_h, ier) -end subroutine mo_diff_2d_n +end subroutine MO_DIFF_2D_N_ !======================================================================= ! The following routines are used by the public interfaces above !======================================================================= -subroutine solve_zeta(rich, z, z0, zt, zq, f_m, f_t, f_q, mask) - -real , intent(in) , dimension(:) :: rich, z, z0, zt, zq -logical, intent(in) , dimension(:) :: mask -real , intent(out), dimension(:) :: f_m, f_t, f_q +subroutine SOLVE_ZETA_(rich, z, z0, zt, zq, f_m, f_t, f_q, mask) +real(kind=FMS_MO_KIND_), intent(in) , dimension(:) :: rich, z, z0, zt, zq +logical, intent(in) , dimension(:) :: mask +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: f_m, f_t, f_q -real, parameter :: error = 1.e-04 -real, parameter :: zeta_min = 1.e-06 -integer, parameter :: max_iter = 20 +integer, parameter :: lkind = FMS_MO_KIND_ +real(kind=FMS_MO_KIND_), parameter :: error = 1.0E-04_lkind +real(kind=FMS_MO_KIND_), parameter :: zeta_min = 1.0E-06_lkind +integer, parameter :: max_iter = 20 -real :: max_cor -integer :: iter +real(kind=FMS_MO_KIND_) :: max_cor +integer :: iter -real, dimension(size(rich(:))) :: & +real(kind=FMS_MO_KIND_), dimension(size(rich(:))) :: & d_rich, rich_1, correction, corr, z_z0, z_zt, z_zq, & ln_z_z0, ln_z_zt, ln_z_zq, zeta, & phi_m, phi_m_0, phi_t, phi_t_0, rzeta, & zeta_0, zeta_t, zeta_q, df_m, df_t -logical, dimension(size(rich(:))) :: mask_1 +logical, dimension(size(rich(:))) :: mask_1 - -z_z0 = z/z0 -z_zt = z/zt -z_zq = z/zq +z_z0 = z/z0 +z_zt = z/zt +z_zq = z/zq ln_z_z0 = log(z_z0) ln_z_zt = log(z_zt) ln_z_zq = log(z_zq) -corr = 0.0 +corr = 0.0_lkind mask_1 = mask ! initial guess @@ -353,32 +191,32 @@ mask_1 = mask where(mask_1) zeta = rich*ln_z_z0*ln_z_z0/ln_z_zt elsewhere - zeta = 0.0 + zeta = 0.0_lkind end where -where (mask_1 .and. rich >= 0.0) - zeta = zeta/(1.0 - rich/rich_crit) +where (mask_1 .and. rich >= 0.0_lkind) + zeta = zeta/(1.0_lkind - rich/real(rich_crit, FMS_MO_KIND_)) end where iter_loop: do iter = 1, max_iter where (mask_1 .and. abs(zeta).lt.zeta_min) - zeta = 0.0 - f_m = ln_z_z0 - f_t = ln_z_zt - f_q = ln_z_zq + zeta = 0.0_lkind + f_m = ln_z_z0 + f_t = ln_z_zt + f_q = ln_z_zq mask_1 = .false. ! don't do any more calculations at these pts end where where (mask_1) - rzeta = 1.0/zeta + rzeta = 1.0_lkind/zeta zeta_0 = zeta/z_z0 zeta_t = zeta/z_zt zeta_q = zeta/z_zq elsewhere - zeta_0 = 0.0 - zeta_t = 0.0 - zeta_q = 0.0 + zeta_0 = 0.0_lkind + zeta_t = 0.0_lkind + zeta_q = 0.0_lkind end where call mo_derivative_m(phi_m , zeta , mask_1) @@ -390,17 +228,17 @@ iter_loop: do iter = 1, max_iter call mo_integral_tq(f_t, f_q, zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq, mask_1) where (mask_1) - df_m = (phi_m - phi_m_0)*rzeta - df_t = (phi_t - phi_t_0)*rzeta - rich_1 = zeta*f_t/(f_m*f_m) - d_rich = rich_1*( rzeta + df_t/f_t - 2.0 *df_m/f_m) + df_m = (phi_m - phi_m_0)*rzeta + df_t = (phi_t - phi_t_0)*rzeta + rich_1 = zeta*f_t/(f_m*f_m) + d_rich = rich_1*( rzeta + df_t/f_t - 2.0_lkind *df_m/f_m) correction = (rich - rich_1)/d_rich - corr = min(abs(correction),abs(correction/zeta)) + corr = min(abs(correction),abs(correction/zeta)) ! the criterion corr < error seems to work ok, but is a bit arbitrary ! when zeta is small the tolerance is reduced end where - max_cor= maxval(corr) + max_cor = maxval(corr) if(max_cor > error) then mask_1 = mask_1 .and. (corr > error) @@ -418,115 +256,120 @@ end do iter_loop call error_mesg ('solve_zeta in monin_obukhov_mod', & 'surface drag iteration did not converge', FATAL) -end subroutine solve_zeta +end subroutine SOLVE_ZETA_ !======================================================================= -subroutine mo_derivative_m(phi_m, zeta, mask) +subroutine MO_DERIVATIVE_M_(phi_m, zeta, mask) ! the differential similarity function for momentum -real , intent(out), dimension(:) :: phi_m -real , intent(in), dimension(:) :: zeta -logical , intent(in), dimension(:) :: mask +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: phi_m +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: zeta +logical, intent(in), dimension(:) :: mask -logical, dimension(size(zeta(:))) :: stable, unstable -real , dimension(size(zeta(:))) :: x +logical, dimension(size(zeta(:))) :: stable, unstable +real(kind=FMS_MO_KIND_), dimension(size(zeta(:))) :: x +integer, parameter :: lkind = FMS_MO_KIND_ -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 +stable = mask .and. zeta >= 0.0_lkind +unstable = mask .and. zeta < 0.0_lkind where (unstable) - x = (1 - 16.0*zeta )**(-0.5) + x = (1.0_lkind - 16.0_lkind*zeta )**(-0.5_lkind) phi_m = sqrt(x) ! phi_m = (1 - 16.0*zeta)**(-0.25) end where if(stable_option == 1) then where (stable) - phi_m = 1.0 + zeta *(5.0 + b_stab*zeta)/(1.0 + zeta) + phi_m = 1.0_lkind + zeta*(5.0_lkind + real(b_stab, FMS_MO_KIND_) & + *zeta)/(1.0_lkind + zeta) end where else if(stable_option == 2) then - where (stable .and. zeta < zeta_trans) - phi_m = 1 + 5.0*zeta + where (stable .and. zeta < real(zeta_trans,FMS_MO_KIND_)) + phi_m = 1.0_lkind + 5.0_lkind*zeta end where - where (stable .and. zeta >= zeta_trans) - phi_m = lambda + b_stab*zeta + where (stable .and. zeta >= real(zeta_trans,FMS_MO_KIND_)) + phi_m = real(lambda, FMS_MO_KIND_) + real(b_stab, FMS_MO_KIND_)*zeta end where endif return -end subroutine mo_derivative_m +end subroutine MO_DERIVATIVE_M_ !======================================================================= -subroutine mo_derivative_t(phi_t, zeta, mask) +subroutine MO_DERIVATIVE_T_(phi_t, zeta, mask) ! the differential similarity function for buoyancy and tracers -real , intent(out), dimension(:) :: phi_t -real , intent(in), dimension(:) :: zeta -logical , intent(in), dimension(:) :: mask +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: phi_t +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: zeta +logical , intent(in), dimension(:) :: mask -logical, dimension(size(zeta(:))) :: stable, unstable +logical, dimension(size(zeta(:))) :: stable, unstable +integer, parameter :: lkind = FMS_MO_KIND_ -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 +stable = mask .and. zeta >= 0.0_lkind +unstable = mask .and. zeta < 0.0_lkind where (unstable) - phi_t = (1 - 16.0*zeta)**(-0.5) + phi_t = (1.0_lkind - 16.0_lkind*zeta)**(-0.5_lkind) end where if(stable_option == 1) then where (stable) - phi_t = 1.0 + zeta*(5.0 + b_stab*zeta)/(1.0 + zeta) + phi_t = 1.0_lkind + zeta * (5.0_lkind + real(b_stab, FMS_MO_KIND_)& + * zeta)/(1.0_lkind + zeta) end where else if(stable_option == 2) then - where (stable .and. zeta < zeta_trans) - phi_t = 1 + 5.0*zeta + where (stable .and. zeta < real(zeta_trans,FMS_MO_KIND_)) + phi_t = 1.0_lkind + 5.0_lkind*zeta end where - where (stable .and. zeta >= zeta_trans) - phi_t = lambda + b_stab*zeta + where (stable .and. zeta >= real(zeta_trans,FMS_MO_KIND_)) + phi_t = real(lambda, FMS_MO_KIND_) + real(b_stab, FMS_MO_KIND_)*zeta end where endif return -end subroutine mo_derivative_t +end subroutine MO_DERIVATIVE_T_ !======================================================================= -subroutine mo_integral_tq (psi_t, psi_q, zeta, zeta_t, zeta_q, & +subroutine MO_INTEGRAL_TQ_ (psi_t, psi_q, zeta, zeta_t, zeta_q, & ln_z_zt, ln_z_zq, mask) ! the integral similarity function for moisture and tracers -real , intent(out), dimension(:) :: psi_t, psi_q -real , intent(in), dimension(:) :: zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq -logical , intent(in), dimension(:) :: mask +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: psi_t, psi_q +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq +logical , intent(in), dimension(:) :: mask -real, dimension(size(zeta(:))) :: x, x_t, x_q +real(kind=FMS_MO_KIND_), dimension(size(zeta(:))) :: x, x_t, x_q -logical, dimension(size(zeta(:))) :: stable, unstable, & - weakly_stable, strongly_stable +logical, dimension(size(zeta(:))) :: stable, unstable, & + weakly_stable, strongly_stable +integer, parameter :: lkind = FMS_MO_KIND_ -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 +stable = mask .and. zeta >= 0.0_lkind +unstable = mask .and. zeta < 0.0_lkind where(unstable) - x = sqrt(1 - 16.0*zeta) - x_t = sqrt(1 - 16.0*zeta_t) - x_q = sqrt(1 - 16.0*zeta_q) + x = sqrt(1.0_lkind - 16.0_lkind*zeta) + x_t = sqrt(1.0_lkind - 16.0_lkind*zeta_t) + x_q = sqrt(1.0_lkind - 16.0_lkind*zeta_q) - psi_t = ln_z_zt - 2.0*log( (1.0 + x)/(1.0 + x_t) ) - psi_q = ln_z_zq - 2.0*log( (1.0 + x)/(1.0 + x_q) ) + psi_t = ln_z_zt - 2.0_lkind*log( (1.0_lkind + x)/(1.0_lkind + x_t) ) + psi_q = ln_z_zq - 2.0_lkind*log( (1.0_lkind + x)/(1.0_lkind + x_q) ) end where @@ -534,113 +377,126 @@ if( stable_option == 1) then where (stable) - psi_t = ln_z_zt + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_t)) & - + b_stab*(zeta - zeta_t) - psi_q = ln_z_zq + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_q)) & - + b_stab*(zeta - zeta_q) + psi_t = ln_z_zt + (5.0_lkind - real(b_stab, FMS_MO_KIND_)) & + *log((1.0_lkind + zeta)/(1.0_lkind + zeta_t)) & + + real(b_stab, FMS_MO_KIND_)*(zeta - zeta_t) + psi_q = ln_z_zq + (5.0_lkind - real(b_stab, FMS_MO_KIND_)) & + *log((1.0_lkind + zeta)/(1.0_lkind + zeta_q)) & + + real(b_stab, FMS_MO_KIND_)*(zeta - zeta_q) end where else if (stable_option == 2) then - weakly_stable = stable .and. zeta <= zeta_trans - strongly_stable = stable .and. zeta > zeta_trans + weakly_stable = stable .and. zeta <= real(zeta_trans,FMS_MO_KIND_) + strongly_stable = stable .and. zeta > real(zeta_trans,FMS_MO_KIND_) where (weakly_stable) - psi_t = ln_z_zt + 5.0*(zeta - zeta_t) - psi_q = ln_z_zq + 5.0*(zeta - zeta_q) + psi_t = ln_z_zt + 5.0_lkind*(zeta - zeta_t) + psi_q = ln_z_zq + 5.0_lkind*(zeta - zeta_q) end where where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) + x = (real(lambda, FMS_MO_KIND_) - 1.0_lkind)*log(zeta/real(zeta_trans, FMS_MO_KIND_)) + & + real(b_stab, FMS_MO_KIND_)*(zeta - real(zeta_trans, FMS_MO_KIND_)) endwhere - where (strongly_stable .and. zeta_t <= zeta_trans) - psi_t = ln_z_zt + x + 5.0*(zeta_trans - zeta_t) + where (strongly_stable .and. zeta_t <= real(zeta_trans,FMS_MO_KIND_)) + psi_t = ln_z_zt + x + 5.0_lkind * (real(zeta_trans, FMS_MO_KIND_) - zeta_t) end where - where (strongly_stable .and. zeta_t > zeta_trans) - psi_t = lambda*ln_z_zt + b_stab*(zeta - zeta_t) + + where (strongly_stable .and. zeta_t > real(zeta_trans,FMS_MO_KIND_)) + psi_t = real(lambda, FMS_MO_KIND_)* ln_z_zt & + + real(b_stab, FMS_MO_KIND_)*(zeta - zeta_t) endwhere - where (strongly_stable .and. zeta_q <= zeta_trans) - psi_q = ln_z_zq + x + 5.0*(zeta_trans - zeta_q) + where (strongly_stable .and. zeta_q <= real(zeta_trans,FMS_MO_KIND_)) + psi_q = ln_z_zq + x + 5.0_lkind & + *(real(zeta_trans, FMS_MO_KIND_) - zeta_q) end where - where (strongly_stable .and. zeta_q > zeta_trans) - psi_q = lambda*ln_z_zq + b_stab*(zeta - zeta_q) + + where (strongly_stable .and. zeta_q > real(zeta_trans,FMS_MO_KIND_)) + psi_q = real(lambda, FMS_MO_KIND_)*ln_z_zq + real(b_stab, FMS_MO_KIND_) & + * (zeta - zeta_q) endwhere end if return -end subroutine mo_integral_tq +end subroutine MO_INTEGRAL_TQ_ !======================================================================= -subroutine mo_integral_m (psi_m, zeta, zeta_0, ln_z_z0, mask) +subroutine MO_INTEGRAL_M_ (psi_m, zeta, zeta_0, ln_z_z0, mask) ! the integral similarity function for momentum -real , intent(out), dimension(:) :: psi_m -real , intent(in), dimension(:) :: zeta, zeta_0, ln_z_z0 -logical , intent(in), dimension(:) :: mask +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: psi_m +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: zeta, zeta_0, ln_z_z0 +logical, intent(in), dimension(:) :: mask -real, dimension(size(zeta(:))) :: x, x_0, x1, x1_0, num, denom, y +real(kind=FMS_MO_KIND_), dimension(size(zeta(:))) :: x, x_0, x1, x1_0, num, denom, y -logical, dimension(size(zeta(:))) :: stable, unstable, & - weakly_stable, strongly_stable +logical, dimension(size(zeta(:))) :: stable, unstable, & + weakly_stable, strongly_stable +integer, parameter :: lkind = FMS_MO_KIND_ -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 +stable = mask .and. zeta >= 0.0_lkind +unstable = mask .and. zeta < 0.0_lkind where(unstable) - x = sqrt(1 - 16.0*zeta) - x_0 = sqrt(1 - 16.0*zeta_0) + x = sqrt(1.0_lkind - 16.0_lkind*zeta) + x_0 = sqrt(1.0_lkind - 16.0_lkind*zeta_0) x = sqrt(x) x_0 = sqrt(x_0) - x1 = 1.0 + x - x1_0 = 1.0 + x_0 + x1 = 1.0_lkind + x + x1_0 = 1.0_lkind + x_0 - num = x1*x1*(1.0 + x*x) - denom = x1_0*x1_0*(1.0 + x_0*x_0) + num = x1*x1*(1.0_lkind + x*x) + denom = x1_0*x1_0*(1.0_lkind + x_0*x_0) y = atan(x) - atan(x_0) - psi_m = ln_z_z0 - log(num/denom) + 2*y + psi_m = ln_z_z0 - log(num/denom) + 2.0_lkind*y end where if( stable_option == 1) then where (stable) - psi_m = ln_z_z0 + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_0)) & - + b_stab*(zeta - zeta_0) + psi_m = ln_z_z0 + (5.0_lkind - real(b_stab, FMS_MO_KIND_)) & + *log((1.0_lkind + zeta)/(1.0_lkind + zeta_0)) & + + real(b_stab, FMS_MO_KIND_)*(zeta - zeta_0) end where else if (stable_option == 2) then - weakly_stable = stable .and. zeta <= zeta_trans - strongly_stable = stable .and. zeta > zeta_trans + weakly_stable = stable .and. zeta <= real(zeta_trans,FMS_MO_KIND_) + strongly_stable = stable .and. zeta > real(zeta_trans,FMS_MO_KIND_) where (weakly_stable) - psi_m = ln_z_z0 + 5.0*(zeta - zeta_0) + psi_m = ln_z_z0 + 5.0_lkind*(zeta - zeta_0) end where where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) + x = (real(lambda, FMS_MO_KIND_) - 1.0_lkind)*log(zeta/real(zeta_trans, FMS_MO_KIND_)) + & + real(b_stab, FMS_MO_KIND_)*(zeta - real(zeta_trans, FMS_MO_KIND_)) endwhere - where (strongly_stable .and. zeta_0 <= zeta_trans) - psi_m = ln_z_z0 + x + 5.0*(zeta_trans - zeta_0) + where (strongly_stable .and. zeta_0 <= real(zeta_trans,FMS_MO_KIND_)) + psi_m = ln_z_z0 + x + 5.0_lkind & + *(real(zeta_trans, FMS_MO_KIND_) - zeta_0) end where - where (strongly_stable .and. zeta_0 > zeta_trans) - psi_m = lambda*ln_z_z0 + b_stab*(zeta - zeta_0) + where (strongly_stable .and. zeta_0 > real(zeta_trans,FMS_MO_KIND_)) + psi_m = real(lambda, FMS_MO_KIND_)*ln_z_z0 + real(b_stab, FMS_MO_KIND_) & + *(zeta - zeta_0) endwhere end if return -end subroutine mo_integral_m +end subroutine MO_INTEGRAL_M_ !======================================================================= @@ -650,33 +506,33 @@ end subroutine mo_integral_m !======================================================================= -subroutine mo_drag_2d & +subroutine MO_DRAG_2D_ & (pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, drag_q, u_star, b_star) -real, intent(in) , dimension(:,:) :: z, speed, pt, pt0, z0, zt, zq -real, intent(out) , dimension(:,:) :: drag_m, drag_t, drag_q -real, intent(inout), dimension(:,:) :: u_star, b_star +real(kind=FMS_MO_KIND_), intent(in) , dimension(:,:) :: z, speed, pt, pt0, z0, zt, zq +real(kind=FMS_MO_KIND_), intent(out) , dimension(:,:) :: drag_m, drag_t, drag_q +real(kind=FMS_MO_KIND_), intent(inout), dimension(:,:) :: u_star, b_star integer :: j do j = 1, size(pt,2) - call mo_drag_1d (pt(:,j), pt0(:,j), z(:,j), z0(:,j), zt(:,j), zq(:,j), & + call mo_drag (pt(:,j), pt0(:,j), z(:,j), z0(:,j), zt(:,j), zq(:,j), & speed(:,j), drag_m(:,j), drag_t(:,j), drag_q(:,j), & u_star(:,j), b_star(:,j)) end do return -end subroutine mo_drag_2d +end subroutine MO_DRAG_2D_ !======================================================================= -subroutine mo_drag_0d & +subroutine MO_DRAG_0D_ & (pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, drag_q, u_star, b_star) -real, intent(in) :: z, speed, pt, pt0, z0, zt, zq -real, intent(out) :: drag_m, drag_t, drag_q, u_star, b_star +real(kind=FMS_MO_KIND_), intent(in) :: z, speed, pt, pt0, z0, zt, zq +real(kind=FMS_MO_KIND_), intent(out) :: drag_m, drag_t, drag_q, u_star, b_star -real, dimension(1) :: pt_1, pt0_1, z_1, z0_1, zt_1, zq_1, speed_1, & +real(kind=FMS_MO_KIND_), dimension(1) :: pt_1, pt0_1, z_1, z0_1, zt_1, zq_1, speed_1, & drag_m_1, drag_t_1, drag_q_1, u_star_1, b_star_1 pt_1 (1) = pt @@ -687,7 +543,7 @@ zt_1 (1) = zt zq_1 (1) = zq speed_1(1) = speed -call mo_drag_1d (pt_1, pt0_1, z_1, z0_1, zt_1, zq_1, speed_1, & +call mo_drag (pt_1, pt0_1, z_1, z0_1, zt_1, zq_1, speed_1, & drag_m_1, drag_t_1, drag_q_1, u_star_1, b_star_1) drag_m = drag_m_1(1) @@ -697,37 +553,37 @@ u_star = u_star_1(1) b_star = b_star_1(1) return -end subroutine mo_drag_0d +end subroutine MO_DRAG_0D_ !======================================================================= -subroutine mo_profile_2d(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & +subroutine MO_PROFILE_2D_(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & del_m, del_h, del_q) -real, intent(in) :: zref, zref_t -real, intent(in) , dimension(:,:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:,:) :: del_m, del_h, del_q +real(kind=FMS_MO_KIND_), intent(in) :: zref, zref_t +real(kind=FMS_MO_KIND_), intent(in) , dimension(:,:) :: z, z0, zt, zq, u_star, b_star, q_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:) :: del_m, del_h, del_q integer :: j do j = 1, size(z,2) - call mo_profile_1d (zref, zref_t, z(:,j), z0(:,j), zt(:,j), & + call mo_profile (zref, zref_t, z(:,j), z0(:,j), zt(:,j), & zq(:,j), u_star(:,j), b_star(:,j), q_star(:,j), & del_m(:,j), del_h (:,j), del_q (:,j)) enddo return -end subroutine mo_profile_2d +end subroutine MO_PROFILE_2D_ !======================================================================= -subroutine mo_profile_0d(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & +subroutine MO_PROFILE_0D_(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & del_m, del_h, del_q) -real, intent(in) :: zref, zref_t -real, intent(in) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out) :: del_m, del_h, del_q +real(kind=FMS_MO_KIND_), intent(in) :: zref, zref_t +real(kind=FMS_MO_KIND_), intent(in) :: z, z0, zt, zq, u_star, b_star, q_star +real(kind=FMS_MO_KIND_), intent(out) :: del_m, del_h, del_q -real, dimension(1) :: z_1, z0_1, zt_1, zq_1, u_star_1, b_star_1, q_star_1, & +real(kind=FMS_MO_KIND_), dimension(1) :: z_1, z0_1, zt_1, zq_1, u_star_1, b_star_1, q_star_1, & del_m_1, del_h_1, del_q_1 z_1 (1) = z @@ -738,7 +594,7 @@ u_star_1(1) = u_star b_star_1(1) = b_star q_star_1(1) = q_star -call mo_profile_1d (zref, zref_t, z_1, z0_1, zt_1, zq_1, & +call mo_profile (zref, zref_t, z_1, z0_1, zt_1, zq_1, & u_star_1, b_star_1, q_star_1, & del_m_1, del_h_1, del_q_1) @@ -748,123 +604,123 @@ del_q = del_q_1(1) return -end subroutine mo_profile_0d +end subroutine MO_PROFILE_0D_ !======================================================================= -subroutine mo_profile_1d_n(zref, z, z0, zt, zq, u_star, b_star, q_star, & +subroutine MO_PROFILE_1D_N_(zref, z, z0, zt, zq, u_star, b_star, q_star, & del_m, del_t, del_q, avail) -real, intent(in), dimension(:) :: zref -real, intent(in) , dimension(:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:,:) :: del_m, del_t, del_q -logical, intent(in) , optional, dimension(:) :: avail +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: zref +real(kind=FMS_MO_KIND_), intent(in) , dimension(:) :: z, z0, zt, zq, u_star, b_star, q_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:) :: del_m, del_t, del_q +logical, intent(in) , optional, dimension(:) :: avail integer :: k do k = 1, size(zref(:)) if(present(avail)) then - call mo_profile_1d (zref(k), zref(k), z, z0, zt, zq, & + call mo_profile (zref(k), zref(k), z, z0, zt, zq, & u_star, b_star, q_star, del_m(:,k), del_t(:,k), del_q(:,k), avail) else - call mo_profile_1d (zref(k), zref(k), z, z0, zt, zq, & + call mo_profile (zref(k), zref(k), z, z0, zt, zq, & u_star, b_star, q_star, del_m(:,k), del_t(:,k), del_q(:,k)) endif enddo return -end subroutine mo_profile_1d_n +end subroutine MO_PROFILE_1D_N_ !======================================================================= -subroutine mo_profile_0d_n(zref, z, z0, zt, zq, u_star, b_star, q_star, & +subroutine MO_PROFILE_0D_N_(zref, z, z0, zt, zq, u_star, b_star, q_star, & del_m, del_t, del_q) -real, intent(in), dimension(:) :: zref -real, intent(in) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:) :: del_m, del_t, del_q +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: zref +real(kind=FMS_MO_KIND_), intent(in) :: z, z0, zt, zq, u_star, b_star, q_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: del_m, del_t, del_q integer :: k do k = 1, size(zref(:)) - call mo_profile_0d (zref(k), zref(k), z, z0, zt, zq, & + call mo_profile (zref(k), zref(k), z, z0, zt, zq, & u_star, b_star, q_star, del_m(k), del_t(k), del_q(k)) enddo return -end subroutine mo_profile_0d_n +end subroutine MO_PROFILE_0D_N_ !======================================================================= -subroutine mo_profile_2d_n(zref, z, z0, zt, zq, u_star, b_star, q_star, & +subroutine MO_PROFILE_2D_N_(zref, z, z0, zt, zq, u_star, b_star, q_star, & del_m, del_t, del_q) -real, intent(in), dimension(:) :: zref -real, intent(in), dimension(:,:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:,:,:) :: del_m, del_t, del_q +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: zref +real(kind=FMS_MO_KIND_), intent(in), dimension(:,:) :: z, z0, zt, zq, u_star, b_star, q_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:,:) :: del_m, del_t, del_q integer :: k do k = 1, size(zref(:)) - call mo_profile_2d (zref(k), zref(k), z, z0, zt, zq, & + call mo_profile (zref(k), zref(k), z, z0, zt, zq, & u_star, b_star, q_star, del_m(:,:,k), del_t(:,:,k), del_q(:,:,k)) enddo return -end subroutine mo_profile_2d_n +end subroutine MO_PROFILE_2D_N_ !======================================================================= -subroutine mo_diff_2d_1(z, u_star, b_star, k_m, k_h) +subroutine MO_DIFF_2D_1_(z, u_star, b_star, k_m, k_h) -real, intent(in), dimension(:,:) :: z, u_star, b_star -real, intent(out), dimension(:,:) :: k_m, k_h +real(kind=FMS_MO_KIND_), intent(in), dimension(:,:) :: z, u_star, b_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:) :: k_m, k_h -real , dimension(size(z,1),size(z,2),1) :: z_n, k_m_n, k_h_n +real(kind=FMS_MO_KIND_), dimension(size(z,1),size(z,2),1) :: z_n, k_m_n, k_h_n z_n(:,:,1) = z -call mo_diff_2d_n(z_n, u_star, b_star, k_m_n, k_h_n) +call mo_diff(z_n, u_star, b_star, k_m_n, k_h_n) k_m = k_m_n(:,:,1) k_h = k_h_n(:,:,1) return -end subroutine mo_diff_2d_1 +end subroutine MO_DIFF_2D_1_ !======================================================================= -subroutine mo_diff_1d_1(z, u_star, b_star, k_m, k_h) +subroutine MO_DIFF_1D_1_(z, u_star, b_star, k_m, k_h) -real, intent(in), dimension(:) :: z, u_star, b_star -real, intent(out), dimension(:) :: k_m, k_h +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: z, u_star, b_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: k_m, k_h -real, dimension(size(z),1,1) :: z_n, k_m_n, k_h_n -real, dimension(size(z),1) :: u_star_n, b_star_n +real(kind=FMS_MO_KIND_), dimension(size(z),1,1) :: z_n, k_m_n, k_h_n +real(kind=FMS_MO_KIND_), dimension(size(z),1) :: u_star_n, b_star_n z_n (:,1,1) = z u_star_n(:,1) = u_star b_star_n(:,1) = b_star -call mo_diff_2d_n(z_n, u_star_n, b_star_n, k_m_n, k_h_n) +call mo_diff(z_n, u_star_n, b_star_n, k_m_n, k_h_n) k_m = k_m_n(:,1,1) k_h = k_h_n(:,1,1) return -end subroutine mo_diff_1d_1 +end subroutine MO_DIFF_1D_1_ !======================================================================= -subroutine mo_diff_1d_n(z, u_star, b_star, k_m, k_h) +subroutine MO_DIFF_1D_N_(z, u_star, b_star, k_m, k_h) -real, intent(in), dimension(:,:) :: z -real, intent(in), dimension(:) :: u_star, b_star -real, intent(out), dimension(:,:) :: k_m, k_h +real(kind=FMS_MO_KIND_), intent(in), dimension(:,:) :: z +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: u_star, b_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:) :: k_m, k_h -real, dimension(size(z,1),1) :: u_star2, b_star2 -real, dimension(size(z,1),1, size(z,2)) :: z2, k_m2, k_h2 +real(kind=FMS_MO_KIND_), dimension(size(z,1),1) :: u_star2, b_star2 +real(kind=FMS_MO_KIND_), dimension(size(z,1),1, size(z,2)) :: z2, k_m2, k_h2 integer :: n @@ -874,7 +730,7 @@ enddo u_star2(:,1) = u_star b_star2(:,1) = b_star -call mo_diff_2d_n(z2, u_star2, b_star2, k_m2, k_h2) +call mo_diff(z2, u_star2, b_star2, k_m2, k_h2) do n = 1, size(z,2) k_m(:,n) = k_m2(:,1,n) @@ -882,69 +738,72 @@ do n = 1, size(z,2) enddo return -end subroutine mo_diff_1d_n +end subroutine MO_DIFF_1D_N_ !======================================================================= -subroutine mo_diff_0d_1(z, u_star, b_star, k_m, k_h) +subroutine MO_DIFF_0D_1_(z, u_star, b_star, k_m, k_h) -real, intent(in) :: z, u_star, b_star -real, intent(out) :: k_m, k_h +real(kind=FMS_MO_KIND_), intent(in) :: z, u_star, b_star +real(kind=FMS_MO_KIND_), intent(out) :: k_m, k_h -integer :: ni, nj, nk, ier -real, parameter :: ustar_min = 1.e-10 -real, dimension(1,1,1) :: z_a, k_m_a, k_h_a -real, dimension(1,1) :: u_star_a, b_star_a +integer :: ni, nj, nk, ier +integer, parameter :: lkind = FMS_MO_KIND_ +real(kind=FMS_MO_KIND_), parameter :: ustar_min = 1.0E-10_lkind +real(kind=FMS_MO_KIND_), dimension(1,1,1) :: z_a, k_m_a, k_h_a +real(kind=FMS_MO_KIND_), dimension(1,1) :: u_star_a, b_star_a if(.not.module_is_initialized) call error_mesg('mo_diff_0d_1 in monin_obukhov_mod', & 'monin_obukhov_init has not been called', FATAL) ni = 1; nj = 1; nk = 1 -z_a(1,1,1) = z +z_a(1,1,1) = z u_star_a(1,1) = u_star b_star_a(1,1) = b_star -call monin_obukhov_diff(vonkarm, & - & ustar_min, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, &!miz - & ni, nj, nk, z_a, u_star_a, b_star_a, k_m_a, k_h_a, ier) +call monin_obukhov_diff(real(vonkarm, FMS_MO_KIND_), ustar_min, neutral, & + & stable_option, new_mo_option, real(rich_crit, FMS_MO_KIND_), & + & real(zeta_trans, FMS_MO_KIND_), ni, nj, nk, z_a, u_star_a, & !miz + & b_star_a, k_m_a, k_h_a, ier) k_m = k_m_a(1,1,1) k_h = k_h_a(1,1,1) -end subroutine mo_diff_0d_1 + +end subroutine MO_DIFF_0D_1_ !======================================================================= -subroutine mo_diff_0d_n(z, u_star, b_star, k_m, k_h) +subroutine MO_DIFF_0D_N_(z, u_star, b_star, k_m, k_h) -real, intent(in), dimension(:) :: z -real, intent(in) :: u_star, b_star -real, intent(out), dimension(:) :: k_m, k_h +real(kind=FMS_MO_KIND_), intent(in), dimension(:) :: z +real(kind=FMS_MO_KIND_), intent(in) :: u_star, b_star +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: k_m, k_h -integer :: ni, nj, nk, ier -real, parameter :: ustar_min = 1.e-10 -real, dimension(1,1,size(z)) :: z_a, k_m_a, k_h_a -real, dimension(1,1) :: u_star_a, b_star_a +integer :: ni, nj, nk, ier +integer, parameter :: lkind = FMS_MO_KIND_ +real(kind=FMS_MO_KIND_), parameter :: ustar_min = 1.0E-10_lkind +real(kind=FMS_MO_KIND_), dimension(1,1,size(z)) :: z_a, k_m_a, k_h_a +real(kind=FMS_MO_KIND_), dimension(1,1) :: u_star_a, b_star_a if(.not.module_is_initialized) call error_mesg('mo_diff_0d_n in monin_obukhov_mod', & 'monin_obukhov_init has not been called', FATAL) ni = 1; nj = 1; nk = size(z(:)) -z_a(1,1,:) = z(:) +z_a(1,1,:) = z(:) u_star_a(1,1) = u_star b_star_a(1,1) = b_star -call monin_obukhov_diff(vonkarm, & - & ustar_min, & - & neutral, stable_option,new_mo_option,rich_crit, zeta_trans, &!miz - & ni, nj, nk, z_a, u_star_a, b_star_a, k_m_a, k_h_a, ier) +call monin_obukhov_diff(real(vonkarm, FMS_MO_KIND_), ustar_min, neutral, & + & stable_option, new_mo_option, real(rich_crit, FMS_MO_KIND_), & + & real(zeta_trans, FMS_MO_KIND_), ni, nj, nk, z_a, u_star_a, & + & b_star_a, k_m_a, k_h_a, ier) k_m(:) = k_m_a(1,1,:) k_h(:) = k_h_a(1,1,:) -end subroutine mo_diff_0d_n +end subroutine MO_DIFF_0D_N_ !======================================================================= -subroutine stable_mix_2d(rich, mix) +subroutine STABLE_MIX_2D_(rich, mix) -real, intent(in) , dimension(:,:) :: rich -real, intent(out), dimension(:,:) :: mix +real(kind=FMS_MO_KIND_), intent(in) , dimension(:,:) :: rich +real(kind=FMS_MO_KIND_), intent(out), dimension(:,:) :: mix integer :: n2 !< Size of dimension 2 of mix and rich integer :: i !< Loop index @@ -954,15 +813,15 @@ do i=1, n2 call stable_mix(rich(:, i), mix(:, i)) enddo -end subroutine stable_mix_2d +end subroutine STABLE_MIX_2D_ !======================================================================= -subroutine stable_mix_1d(rich, mix) +subroutine STABLE_MIX_1D_(rich, mix) -real, intent(in) , dimension(:) :: rich -real, intent(out), dimension(:) :: mix +real(kind=FMS_MO_KIND_), intent(in) , dimension(:) :: rich +real(kind=FMS_MO_KIND_), intent(out), dimension(:) :: mix integer :: n !< Size of mix and rich integer :: ierr !< Error code set by monin_obukhov_stable_mix @@ -971,27 +830,25 @@ if (.not.module_is_initialized) call error_mesg('stable_mix in monin_obukhov_mod n = size(mix) -call monin_obukhov_stable_mix(stable_option, rich_crit, zeta_trans, & - & n, rich, mix, ierr) +call monin_obukhov_stable_mix(stable_option, real(rich_crit,FMS_MO_KIND_), & + & real(zeta_trans,FMS_MO_KIND_), n, rich, mix, ierr) -end subroutine stable_mix_1d +end subroutine STABLE_MIX_1D_ !======================================================================= -subroutine stable_mix_0d(rich, mix) - -real, intent(in) :: rich -real, intent(out) :: mix +subroutine STABLE_MIX_0D_(rich, mix) -real, dimension(1) :: mix_1d !< Representation of mix as a dimension(1) array +real(kind=FMS_MO_KIND_), intent(in) :: rich +real(kind=FMS_MO_KIND_), intent(out) :: mix +real(kind=FMS_MO_KIND_), dimension(1) :: mix_1d !< Representation of mix as a dimension(1) array call stable_mix([rich], mix_1d) mix = mix_1d(1) -end subroutine stable_mix_0d +end subroutine STABLE_MIX_0D_ !======================================================================= -end module monin_obukhov_mod !> @} ! close documentation grouping diff --git a/monin_obukhov/include/monin_obukhov_inter.inc b/monin_obukhov/include/monin_obukhov_inter.inc index 9aa43e8a0e..12eb2a8abc 100644 --- a/monin_obukhov/include/monin_obukhov_inter.inc +++ b/monin_obukhov/include/monin_obukhov_inter.inc @@ -16,50 +16,30 @@ !* You should have received a copy of the GNU Lesser General Public !* License along with FMS. If not, see . !*********************************************************************** -!> @defgroup monin_obukhov_inter monin_obukhov_inter -!> @ingroup monin_obukhov -!> @brief Utility routines to be used in @ref monin_obukhov_mod !> @addtogroup monin_obukhov_inter !> @{ -module monin_obukhov_inter -implicit none -private -public :: monin_obukhov_diff -public :: monin_obukhov_drag_1d -public :: monin_obukhov_solve_zeta -public :: monin_obukhov_derivative_t -public :: monin_obukhov_derivative_m -public :: monin_obukhov_profile_1d -public :: monin_obukhov_integral_m -public :: monin_obukhov_integral_tq -public :: monin_obukhov_stable_mix - - -contains - - -pure subroutine monin_obukhov_diff(vonkarm, & +pure subroutine MONIN_OBUKHOV_DIFF_(vonkarm, & & ustar_min, & & neutral, stable_option,new_mo_option,rich_crit, zeta_trans, & & ni, nj, nk, z, u_star, b_star, k_m, k_h, ier) - real , intent(in ) :: vonkarm - real , intent(in ) :: ustar_min !< = 1.e-10 - logical, intent(in ) :: neutral - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option !miz - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: ni, nj, nk - real , intent(in ), dimension(ni, nj, nk) :: z - real , intent(in ), dimension(ni, nj) :: u_star, b_star - real , intent( out), dimension(ni, nj, nk) :: k_m, k_h - integer, intent( out) :: ier - - real , dimension(ni, nj) :: phi_m, phi_h, zeta, uss - integer :: j, k + real(kind=FMS_MO_KIND_), intent(in) :: vonkarm + real(kind=FMS_MO_KIND_), intent(in) :: ustar_min !< = 1.0E-10 + logical, intent(in) :: neutral + integer, intent(in) :: stable_option + logical, intent(in) :: new_mo_option !miz + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: ni, nj, nk + real(kind=FMS_MO_KIND_), intent(in), dimension(ni, nj, nk) :: z + real(kind=FMS_MO_KIND_), intent(in), dimension(ni, nj) :: u_star, b_star + real(kind=FMS_MO_KIND_), intent(out), dimension(ni, nj, nk) :: k_m, k_h + integer, intent(out) :: ier + + real(kind=FMS_MO_KIND_), dimension(ni, nj) :: phi_m, phi_h, zeta, uss + integer :: j, k logical, dimension(ni) :: mask ier = 0 @@ -86,51 +66,52 @@ pure subroutine monin_obukhov_diff(vonkarm, & end do endif -end subroutine monin_obukhov_diff +end subroutine MONIN_OBUKHOV_DIFF_ -pure subroutine monin_obukhov_drag_1d(grav, vonkarm, & +pure subroutine MONIN_OBUKHOV_DRAG_1D_(grav, vonkarm, & & error, zeta_min, max_iter, small, & & neutral, stable_option, new_mo_option, rich_crit, zeta_trans,& & drag_min_heat, drag_min_moist, drag_min_mom, & & n, pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, & & drag_q, u_star, b_star, lavail, avail, ier) - real , intent(in ) :: grav - real , intent(in ) :: vonkarm - real , intent(in ) :: error !< = 1.e-04 - real , intent(in ) :: zeta_min !< = 1.e-06 - integer, intent(in ) :: max_iter !< = 20 - real , intent(in ) :: small !< = 1.e-04 - logical, intent(in ) :: neutral - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option - real , intent(in ) :: rich_crit, zeta_trans - real , intent(in ) :: drag_min_heat, drag_min_moist, drag_min_mom - integer, intent(in ) :: n - real , intent(in ), dimension(n) :: pt, pt0, z, z0, zt, zq, speed - real , intent(inout), dimension(n) :: drag_m, drag_t, drag_q, u_star, b_star - logical, intent(in ) :: lavail !< whether to use provided mask or not - logical, intent(in ), dimension(n) :: avail !< provided mask - integer, intent(out ) :: ier - - real , dimension(n) :: rich, fm, ft, fq, zz - logical, dimension(n) :: mask, mask_1, mask_2 - real , dimension(n) :: delta_b !!, us, bs, qs - real :: r_crit, sqrt_drag_min_heat - real :: sqrt_drag_min_moist, sqrt_drag_min_mom - real :: us, bs, qs - integer :: i + real(kind=FMS_MO_KIND_), intent(in) :: grav + real(kind=FMS_MO_KIND_), intent(in) :: vonkarm + real(kind=FMS_MO_KIND_), intent(in) :: error !< = 1.0E-04 + real(kind=FMS_MO_KIND_), intent(in) :: zeta_min !< = 1.0E-06 + integer, intent(in) :: max_iter !< = 20 + real(kind=FMS_MO_KIND_), intent(in) :: small !< = 1.0E-04 + logical, intent(in) :: neutral + integer, intent(in) :: stable_option + logical, intent(in) :: new_mo_option + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + real(kind=FMS_MO_KIND_), intent(in) :: drag_min_heat, drag_min_moist, drag_min_mom + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(in), dimension(n) :: pt, pt0, z, z0, zt, zq, speed + real(kind=FMS_MO_KIND_), intent(inout), dimension(n) :: drag_m, drag_t, drag_q, u_star, b_star + logical, intent(in) :: lavail !< whether to use provided mask or not + logical, intent(in), dimension(n) :: avail !< provided mask + integer, intent(out) :: ier + + real(kind=FMS_MO_KIND_), dimension(n) :: rich, fm, ft, fq, zz + logical, dimension(n) :: mask, mask_1, mask_2 + real(kind=FMS_MO_KIND_), dimension(n) :: delta_b !!, us, bs, qs + real(kind=FMS_MO_KIND_) :: r_crit, sqrt_drag_min_heat + real(kind=FMS_MO_KIND_) :: sqrt_drag_min_moist, sqrt_drag_min_mom + real(kind=FMS_MO_KIND_) :: us, bs, qs + integer :: i + integer, parameter :: lkind = FMS_MO_KIND_ ier = 0 - r_crit = 0.95*rich_crit ! convergence can get slow if one is + r_crit = 0.95_lkind*rich_crit ! convergence can get slow if one is ! close to rich_crit - sqrt_drag_min_heat = 0.0 - if(drag_min_heat.ne.0.0) sqrt_drag_min_heat = sqrt(drag_min_heat) - sqrt_drag_min_moist = 0.0 - if(drag_min_moist.ne.0.0) sqrt_drag_min_moist = sqrt(drag_min_moist) - sqrt_drag_min_mom = 0.0 - if(drag_min_mom.ne.0.0) sqrt_drag_min_mom = sqrt(drag_min_mom) + sqrt_drag_min_heat = 0.0_lkind + if(drag_min_heat.ne.0.0_lkind) sqrt_drag_min_heat = sqrt(drag_min_heat) + sqrt_drag_min_moist = 0.0_lkind + if(drag_min_moist.ne.0.0_lkind) sqrt_drag_min_moist = sqrt(drag_min_moist) + sqrt_drag_min_mom = 0.0_lkind + if(drag_min_mom.ne.0.0_lkind) sqrt_drag_min_mom = sqrt(drag_min_mom) mask = .true. if(lavail) mask = avail @@ -140,22 +121,22 @@ pure subroutine monin_obukhov_drag_1d(grav, vonkarm, & rich = - z*delta_b/(speed*speed + small) zz = max(z,z0,zt,zq) elsewhere - rich = 0.0 + rich = 0.0_lkind end where if(neutral) then do i = 1, n if(mask(i)) then - fm(i) = log(zz(i)/z0(i)) - ft(i) = log(zz(i)/zt(i)) - fq(i) = log(zz(i)/zq(i)) - us = vonkarm/fm(i) - bs = vonkarm/ft(i) - qs = vonkarm/fq(i) - drag_m(i) = us*us - drag_t(i) = us*bs - drag_q(i) = us*qs + fm(i) = log(zz(i)/z0(i)) + ft(i) = log(zz(i)/zt(i)) + fq(i) = log(zz(i)/zq(i)) + us = vonkarm/fm(i) + bs = vonkarm/ft(i) + qs = vonkarm/fq(i) + drag_m(i) = us*us + drag_t(i) = us*bs + drag_q(i) = us*qs u_star(i) = us*speed(i) b_star(i) = bs*delta_b(i) end if @@ -168,13 +149,13 @@ pure subroutine monin_obukhov_drag_1d(grav, vonkarm, & do i = 1, n if(mask_2(i)) then - drag_m(i) = drag_min_mom - drag_t(i) = drag_min_heat - drag_q(i) = drag_min_moist - us = sqrt_drag_min_mom - bs = sqrt_drag_min_heat - u_star(i) = us*speed(i) - b_star(i) = bs*delta_b(i) + drag_m(i) = drag_min_mom + drag_t(i) = drag_min_heat + drag_q(i) = drag_min_moist + us = sqrt_drag_min_mom + bs = sqrt_drag_min_heat + u_star(i) = us*speed(i) + b_star(i) = bs*delta_b(i) end if enddo @@ -184,75 +165,76 @@ pure subroutine monin_obukhov_drag_1d(grav, vonkarm, & do i = 1, n if(mask_1(i)) then - us = max(vonkarm/fm(i), sqrt_drag_min_mom) - bs = max(vonkarm/ft(i), sqrt_drag_min_heat) - qs = max(vonkarm/fq(i), sqrt_drag_min_moist) - drag_m(i) = us*us - drag_t(i) = us*bs - drag_q(i) = us*qs - u_star(i) = us*speed(i) - b_star(i) = bs*delta_b(i) + us = max(vonkarm/fm(i), sqrt_drag_min_mom) + bs = max(vonkarm/ft(i), sqrt_drag_min_heat) + qs = max(vonkarm/fq(i), sqrt_drag_min_moist) + drag_m(i) = us*us + drag_t(i) = us*bs + drag_q(i) = us*qs + u_star(i) = us*speed(i) + b_star(i) = bs*delta_b(i) endif enddo end if -end subroutine monin_obukhov_drag_1d +end subroutine MONIN_OBUKHOV_DRAG_1D_ -pure subroutine monin_obukhov_solve_zeta(error, zeta_min, max_iter, small, & +pure subroutine MONIN_OBUKHOV_SOLVE_ZETA_(error, zeta_min, max_iter, small, & & stable_option, new_mo_option, rich_crit, zeta_trans, & !miz & n, rich, z, z0, zt, zq, f_m, f_t, f_q, mask, ier) - real , intent(in ) :: error !< = 1.e-04 - real , intent(in ) :: zeta_min !< = 1.e-06 - integer, intent(in ) :: max_iter !< = 20 - real , intent(in ) :: small !< = 1.e-04 - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(in ), dimension(n) :: rich, z, z0, zt, zq - logical, intent(in ), dimension(n) :: mask - real , intent( out), dimension(n) :: f_m, f_t, f_q - integer, intent( out) :: ier - - real :: max_cor - integer :: iter - real, dimension(n) :: & + real(kind=FMS_MO_KIND_), intent(in) :: error !< = 1.0E-04 + real(kind=FMS_MO_KIND_), intent(in) :: zeta_min !< = 1.0E-06 + integer, intent(in) :: max_iter !< = 20 + real(kind=FMS_MO_KIND_), intent(in) :: small !< = 1.0E-04 + integer, intent(in) :: stable_option + logical, intent(in) :: new_mo_option + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(in), dimension(n) :: rich, z, z0, zt, zq + logical, intent(in), dimension(n) :: mask + real(kind=FMS_MO_KIND_), intent(out), dimension(n) :: f_m, f_t, f_q + integer, intent(out) :: ier + + real(kind=FMS_MO_KIND_) :: max_cor + integer :: iter + real(kind=FMS_MO_KIND_), dimension(n) :: & d_rich, rich_1, correction, corr, z_z0, z_zt, z_zq, & ln_z_z0, ln_z_zt, ln_z_zq, zeta, & phi_m, phi_m_0, phi_t, phi_t_0, rzeta, & zeta_0, zeta_t, zeta_q, df_m, df_t - logical, dimension(n) :: mask_1 + logical, dimension(n) :: mask_1 + integer, parameter :: lkind = FMS_MO_KIND_ ier = 0 - z_z0 = z/z0 - z_zt = z/zt - z_zq = z/zq + z_z0 = z/z0 + z_zt = z/zt + z_zq = z/zq ln_z_z0 = log(z_z0) ln_z_zt = log(z_zt) ln_z_zq = log(z_zq) - corr = 0.0 + corr = 0.0_lkind mask_1 = mask ! initial guess - zeta = 0.0 + zeta = 0.0_lkind where(mask_1) zeta = rich*ln_z_z0*ln_z_z0/ln_z_zt end where - where (mask_1 .and. rich >= 0.0) - zeta = zeta/(1.0 - rich/rich_crit) + where (mask_1 .and. rich >= 0.0_lkind) + zeta = zeta/(1.0_lkind - rich/rich_crit) end where iter_loop: do iter = 1, max_iter where (mask_1 .and. abs(zeta).lt.zeta_min) - zeta = 0.0 + zeta = 0.0_lkind f_m = ln_z_z0 f_t = ln_z_zt f_q = ln_z_zq @@ -260,11 +242,11 @@ pure subroutine monin_obukhov_solve_zeta(error, zeta_min, max_iter, small, & end where - zeta_0 = 0.0 - zeta_t = 0.0 - zeta_q = 0.0 + zeta_0 = 0.0_lkind + zeta_t = 0.0_lkind + zeta_q = 0.0_lkind where (mask_1) - rzeta = 1.0/zeta + rzeta = 1.0_lkind/zeta zeta_0 = zeta/z_z0 zeta_t = zeta/z_zt zeta_q = zeta/z_zq @@ -285,17 +267,17 @@ pure subroutine monin_obukhov_solve_zeta(error, zeta_min, max_iter, small, & & n, f_t, f_q, zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq, mask_1, ier) where (mask_1) - df_m = (phi_m - phi_m_0)*rzeta - df_t = (phi_t - phi_t_0)*rzeta - rich_1 = zeta*f_t/(f_m*f_m) - d_rich = rich_1*( rzeta + df_t/f_t - 2.0 *df_m/f_m) + df_m = (phi_m - phi_m_0)*rzeta + df_t = (phi_t - phi_t_0)*rzeta + rich_1 = zeta*f_t/(f_m*f_m) + d_rich = rich_1*( rzeta + df_t/f_t - 2.0_lkind *df_m/f_m) correction = (rich - rich_1)/d_rich - corr = min(abs(correction),abs(correction/zeta)) + corr = min(abs(correction),abs(correction/zeta)) ! the criterion corr < error seems to work ok, but is a bit arbitrary ! when zeta is small the tolerance is reduced end where - max_cor= maxval(corr) + max_cor = maxval(corr) if(max_cor > error) then mask_1 = mask_1 .and. (corr > error) @@ -312,40 +294,41 @@ pure subroutine monin_obukhov_solve_zeta(error, zeta_min, max_iter, small, & ier = 1 ! surface drag iteration did not converge -end subroutine monin_obukhov_solve_zeta +end subroutine MONIN_OBUKHOV_SOLVE_ZETA_ !> The differential similarity function for buoyancy and tracers ! seems to be the same as monin_obukhov_derivative_m? -pure subroutine monin_obukhov_derivative_t(stable_option,new_mo_option,rich_crit, zeta_trans, & +pure subroutine MONIN_OBUKHOV_DERIVATIVE_T_(stable_option,new_mo_option,rich_crit, zeta_trans, & & n, phi_t, zeta, mask, ier) - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option !miz - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent( out), dimension(n) :: phi_t - real , intent(in ), dimension(n) :: zeta - logical, intent(in ), dimension(n) :: mask - integer, intent( out) :: ier + integer, intent(in) :: stable_option + logical, intent(in) :: new_mo_option !miz + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(out), dimension(n) :: phi_t + real(kind=FMS_MO_KIND_), intent(in), dimension(n) :: zeta + logical, intent(in), dimension(n) :: mask + integer, intent(out) :: ier - logical, dimension(n) :: stable, unstable - real :: b_stab, lambda + logical, dimension(n) :: stable, unstable + real(kind=FMS_MO_KIND_) :: b_stab, lambda + integer, parameter :: lkind = FMS_MO_KIND_ - ier = 0 - b_stab = 1.0/rich_crit + ier = 0 + b_stab = 1.0_lkind/rich_crit - stable = mask .and. zeta >= 0.0 - unstable = mask .and. zeta < 0.0 + stable = mask .and. zeta >= 0.0_lkind + unstable = mask .and. zeta < 0.0_lkind !miz: modified to include new monin-obukhov option if (new_mo_option) then where (unstable) - phi_t = (1 - 16.0*zeta)**(-1./3.) + phi_t = (1.0_lkind - 16.0_lkind*zeta)**(-1.0_lkind/3.0_lkind) end where else where (unstable) - phi_t = (1 - 16.0*zeta)**(-0.5) + phi_t = (1.0_lkind - 16.0_lkind*zeta)**(-0.5_lkind) end where end if !miz @@ -353,15 +336,15 @@ pure subroutine monin_obukhov_derivative_t(stable_option,new_mo_option,rich_crit if(stable_option == 1) then where (stable) - phi_t = 1.0 + zeta*(5.0 + b_stab*zeta)/(1.0 + zeta) + phi_t = 1.0_lkind + zeta*(5.0_lkind + b_stab*zeta)/(1.0_lkind + zeta) end where else if(stable_option == 2) then - lambda = 1.0 + (5.0 - b_stab)*zeta_trans + lambda = 1.0_lkind + (5.0_lkind - b_stab)*zeta_trans where (stable .and. zeta < zeta_trans) - phi_t = 1 + 5.0*zeta + phi_t = 1.0_lkind + 5.0_lkind*zeta end where where (stable .and. zeta >= zeta_trans) phi_t = lambda + b_stab*zeta @@ -369,48 +352,49 @@ pure subroutine monin_obukhov_derivative_t(stable_option,new_mo_option,rich_crit endif -end subroutine monin_obukhov_derivative_t +end subroutine MONIN_OBUKHOV_DERIVATIVE_T_ ! the differential similarity function for momentum -pure subroutine monin_obukhov_derivative_m(stable_option, rich_crit, zeta_trans, & +pure subroutine MONIN_OBUKHOV_DERIVATIVE_M_(stable_option, rich_crit, zeta_trans, & & n, phi_m, zeta, mask, ier) - integer, intent(in ) :: stable_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent( out), dimension(n) :: phi_m - real , intent(in ), dimension(n) :: zeta - logical, intent(in ), dimension(n) :: mask - integer, intent(out ) :: ier + integer, intent(in) :: stable_option + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(out), dimension(n) :: phi_m + real(kind=FMS_MO_KIND_), intent(in), dimension(n) :: zeta + logical, intent(in), dimension(n) :: mask + integer, intent(out) :: ier - logical, dimension(n) :: stable, unstable - real , dimension(n) :: x - real :: b_stab, lambda + logical, dimension(n) :: stable, unstable + real(kind=FMS_MO_KIND_), dimension(n) :: x + real(kind=FMS_MO_KIND_) :: b_stab, lambda + integer, parameter :: lkind = FMS_MO_KIND_ - ier = 0 - b_stab = 1.0/rich_crit + ier = 0 + b_stab = 1.0_lkind/rich_crit - stable = mask .and. zeta >= 0.0 - unstable = mask .and. zeta < 0.0 + stable = mask .and. zeta >= 0.0_lkind + unstable = mask .and. zeta < 0.0_lkind where (unstable) - x = (1 - 16.0*zeta )**(-0.5) - phi_m = sqrt(x) ! phi_m = (1 - 16.0*zeta)**(-0.25) + x = (1.0_lkind - 16.0_lkind*zeta )**(-0.5_lkind) + phi_m = sqrt(x) ! phi_m = (1 - 16.0*zeta)**(-0.25) end where if(stable_option == 1) then where (stable) - phi_m = 1.0 + zeta *(5.0 + b_stab*zeta)/(1.0 + zeta) + phi_m = 1.0_lkind + zeta *(5.0_lkind + b_stab*zeta)/(1.0_lkind + zeta) end where else if(stable_option == 2) then - lambda = 1.0 + (5.0 - b_stab)*zeta_trans + lambda = 1.0_lkind + (5.0_lkind - b_stab)*zeta_trans where (stable .and. zeta < zeta_trans) - phi_m = 1 + 5.0*zeta + phi_m = 1.0_lkind + 5.0_lkind*zeta end where where (stable .and. zeta >= zeta_trans) phi_m = lambda + b_stab*zeta @@ -418,41 +402,42 @@ pure subroutine monin_obukhov_derivative_m(stable_option, rich_crit, zeta_trans, endif -end subroutine monin_obukhov_derivative_m +end subroutine MONIN_OBUKHOV_DERIVATIVE_M_ -pure subroutine monin_obukhov_profile_1d(vonkarm, & +pure subroutine MONIN_OBUKHOV_PROFILE_1D_(vonkarm, & & neutral, stable_option, new_mo_option, rich_crit, zeta_trans, & & n, zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & & del_m, del_t, del_q, lavail, avail, ier) - real , intent(in ) :: vonkarm - logical, intent(in ) :: neutral - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real, intent(in ) :: zref, zref_t - real, intent(in ), dimension(n) :: z, z0, zt, zq, u_star, b_star, q_star - real, intent( out), dimension(n) :: del_m, del_t, del_q - logical, intent(in ) :: lavail !< whether to use provided mask or not - logical, intent(in ), dimension(n) :: avail !< provided mask - integer, intent(out ) :: ier - - real, dimension(n) :: zeta, zeta_0, zeta_t, zeta_q, zeta_ref, zeta_ref_t, & + real(kind=FMS_MO_KIND_), intent(in) :: vonkarm + logical, intent(in) :: neutral + integer, intent(in) :: stable_option + logical, intent(in) :: new_mo_option + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(in) :: zref, zref_t + real(kind=FMS_MO_KIND_), intent(in), dimension(n) :: z, z0, zt, zq, u_star, b_star, q_star + real(kind=FMS_MO_KIND_), intent(out), dimension(n) :: del_m, del_t, del_q + logical, intent(in) :: lavail !< whether to use provided mask or not + logical, intent(in), dimension(n) :: avail !< provided mask + integer, intent(out) :: ier + + real(kind=FMS_MO_KIND_), dimension(n) :: zeta, zeta_0, zeta_t, zeta_q, zeta_ref, zeta_ref_t, & ln_z_z0, ln_z_zt, ln_z_zq, ln_z_zref, ln_z_zref_t, & f_m_ref, f_m, f_t_ref, f_t, f_q_ref, f_q, & mo_length_inv - logical, dimension(n) :: mask + logical, dimension(n) :: mask + integer, parameter :: lkind = FMS_MO_KIND_ ier = 0 mask = .true. if(lavail) mask = avail - del_m = 0.0 ! zero output arrays - del_t = 0.0 - del_q = 0.0 + del_m = 0.0_lkind ! zero output arrays + del_t = 0.0_lkind + del_q = 0.0_lkind where(mask) ln_z_z0 = log(z/z0) @@ -465,21 +450,21 @@ pure subroutine monin_obukhov_profile_1d(vonkarm, & if(neutral) then where(mask) - del_m = 1.0 - ln_z_zref /ln_z_z0 - del_t = 1.0 - ln_z_zref_t/ln_z_zt - del_q = 1.0 - ln_z_zref_t/ln_z_zq + del_m = 1.0_lkind - ln_z_zref /ln_z_z0 + del_t = 1.0_lkind - ln_z_zref_t/ln_z_zt + del_q = 1.0_lkind - ln_z_zref_t/ln_z_zq endwhere else - where(mask .and. u_star > 0.0) + where(mask .and. u_star > 0.0_lkind) mo_length_inv = - vonkarm * b_star/(u_star*u_star) - zeta = z *mo_length_inv - zeta_0 = z0 *mo_length_inv - zeta_t = zt *mo_length_inv - zeta_q = zq *mo_length_inv - zeta_ref = zref *mo_length_inv - zeta_ref_t = zref_t*mo_length_inv + zeta = z *mo_length_inv + zeta_0 = z0 *mo_length_inv + zeta_t = zt *mo_length_inv + zeta_q = zq *mo_length_inv + zeta_ref = zref *mo_length_inv + zeta_ref_t = zref_t*mo_length_inv endwhere call monin_obukhov_integral_m(stable_option, rich_crit, zeta_trans, & @@ -493,83 +478,84 @@ pure subroutine monin_obukhov_profile_1d(vonkarm, & & n, f_t_ref, f_q_ref, zeta, zeta_ref_t, zeta_ref_t, ln_z_zref_t, ln_z_zref_t, mask, ier) where(mask) - del_m = 1.0 - f_m_ref/f_m - del_t = 1.0 - f_t_ref/f_t - del_q = 1.0 - f_q_ref/f_q + del_m = 1.0_lkind - f_m_ref/f_m + del_t = 1.0_lkind - f_t_ref/f_t + del_q = 1.0_lkind - f_q_ref/f_q endwhere end if -end subroutine monin_obukhov_profile_1d +end subroutine MONIN_OBUKHOV_PROFILE_1D_ !> The integral similarity function for momentum -pure subroutine monin_obukhov_integral_m(stable_option, rich_crit, zeta_trans, & +pure subroutine MONIN_OBUKHOV_INTEGRAL_M_(stable_option, rich_crit, zeta_trans, & & n, psi_m, zeta, zeta_0, ln_z_z0, mask, ier) - integer, intent(in ) :: stable_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(inout), dimension(n) :: psi_m - real , intent(in) , dimension(n) :: zeta, zeta_0, ln_z_z0 - logical, intent(in) , dimension(n) :: mask - integer, intent(out) :: ier + integer, intent(in) :: stable_option + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(inout), dimension(n) :: psi_m + real(kind=FMS_MO_KIND_), intent(in) , dimension(n) :: zeta, zeta_0, ln_z_z0 + logical, intent(in) , dimension(n) :: mask + integer, intent(out) :: ier - real :: b_stab, lambda - real, dimension(n) :: x, x_0, x1, x1_0, num, denom, y - logical, dimension(n) :: stable, unstable, & - weakly_stable, strongly_stable + real(kind=FMS_MO_KIND_) :: b_stab, lambda + real(kind=FMS_MO_KIND_), dimension(n) :: x, x_0, x1, x1_0, num, denom, y + logical, dimension(n) :: stable, unstable, & + weakly_stable, strongly_stable + integer, parameter :: lkind = FMS_MO_KIND_ - ier = 0 + ier = 0 - b_stab = 1.0/rich_crit + b_stab = 1.0_lkind/rich_crit - stable = mask .and. zeta >= 0.0 - unstable = mask .and. zeta < 0.0 + stable = mask .and. zeta >= 0.0_lkind + unstable = mask .and. zeta < 0.0_lkind where(unstable) - x = sqrt(1 - 16.0*zeta) - x_0 = sqrt(1 - 16.0*zeta_0) + x = sqrt(1.0_lkind - 16.0_lkind*zeta) + x_0 = sqrt(1.0_lkind - 16.0_lkind*zeta_0) x = sqrt(x) x_0 = sqrt(x_0) - x1 = 1.0 + x - x1_0 = 1.0 + x_0 + x1 = 1.0_lkind + x + x1_0 = 1.0_lkind + x_0 - num = x1*x1*(1.0 + x*x) - denom = x1_0*x1_0*(1.0 + x_0*x_0) + num = x1*x1*(1.0_lkind + x*x) + denom = x1_0*x1_0*(1.0_lkind + x_0*x_0) y = atan(x) - atan(x_0) - psi_m = ln_z_z0 - log(num/denom) + 2*y + psi_m = ln_z_z0 - log(num/denom) + 2.0_lkind*y end where if( stable_option == 1) then where (stable) - psi_m = ln_z_z0 + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_0)) & + psi_m = ln_z_z0 + (5.0_lkind - b_stab)*log((1.0_lkind + zeta)/(1.0_lkind + zeta_0)) & + b_stab*(zeta - zeta_0) end where else if (stable_option == 2) then - lambda = 1.0 + (5.0 - b_stab)*zeta_trans + lambda = 1.0_lkind + (5.0_lkind - b_stab)*zeta_trans weakly_stable = stable .and. zeta <= zeta_trans strongly_stable = stable .and. zeta > zeta_trans where (weakly_stable) - psi_m = ln_z_z0 + 5.0*(zeta - zeta_0) + psi_m = ln_z_z0 + 5.0_lkind*(zeta - zeta_0) end where where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) + x = (lambda - 1.0_lkind)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) endwhere where (strongly_stable .and. zeta_0 <= zeta_trans) - psi_m = ln_z_z0 + x + 5.0*(zeta_trans - zeta_0) + psi_m = ln_z_z0 + x + 5.0_lkind*(zeta_trans - zeta_0) end where where (strongly_stable .and. zeta_0 > zeta_trans) psi_m = lambda*ln_z_z0 + b_stab*(zeta - zeta_0) @@ -577,57 +563,60 @@ pure subroutine monin_obukhov_integral_m(stable_option, rich_crit, zeta_trans, & end if -end subroutine monin_obukhov_integral_m +end subroutine MONIN_OBUKHOV_INTEGRAL_M_ !> The integral similarity function for moisture and tracers -pure subroutine monin_obukhov_integral_tq(stable_option, new_mo_option, rich_crit, zeta_trans, & +pure subroutine MONIN_OBUKHOV_INTEGRAL_TQ_(stable_option, new_mo_option, rich_crit, zeta_trans, & & n, psi_t, psi_q, zeta, zeta_t, zeta_q, & & ln_z_zt, ln_z_zq, mask, ier) - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option !miz - real, intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(inout), dimension(n) :: psi_t, psi_q - real , intent(in) , dimension(n) :: zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq - logical, intent(in) , dimension(n) :: mask - integer, intent( out) :: ier - - real, dimension(n) :: x, x_t, x_q - logical, dimension(n) :: stable, unstable, & - weakly_stable, strongly_stable - real :: b_stab, lambda - real :: s3 !miz + integer, intent(in) :: stable_option + logical, intent(in) :: new_mo_option !miz + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(inout), dimension(n) :: psi_t, psi_q + real(kind=FMS_MO_KIND_), intent(in) , dimension(n) :: zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq + logical, intent(in) , dimension(n) :: mask + integer, intent(out) :: ier + + real(kind=FMS_MO_KIND_), dimension(n) :: x, x_t, x_q + logical, dimension(n) :: stable, unstable, & + weakly_stable, strongly_stable + real(kind=FMS_MO_KIND_) :: b_stab, lambda + real(kind=FMS_MO_KIND_) :: s3 !miz + integer, parameter :: lkind = FMS_MO_KIND_ ier = 0 - b_stab = 1.0/rich_crit + b_stab = 1.0_lkind/rich_crit -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 +stable = mask .and. zeta >= 0.0_lkind +unstable = mask .and. zeta < 0.0_lkind !miz: modified to include a new monin-obukhov option if (new_mo_option) then - s3 = sqrt(3.0) + s3 = sqrt(3.0_lkind) where(unstable) - x = (1 - 16.0*zeta)**(1./3.) - x_t = (1 - 16.0*zeta_t)**(1./3.) - x_q = (1 - 16.0*zeta_q)**(1./3.) - - psi_t = ln_z_zt - 1.5*log((x**2+x+1)/(x_t**2 + x_t + 1)) + s3*(atan((2*x+1)/s3) - atan((2*x_t + 1)/s3)) - psi_q = ln_z_zq - 1.5*log((x**2+x+1)/(x_q**2 + x_q + 1)) + s3*(atan((2*x+1)/s3) - atan((2*x_q + 1)/s3)) + x = (1.0_lkind - 16.0_lkind*zeta)**(1.0_lkind/3.0_lkind) + x_t = (1.0_lkind - 16.0_lkind*zeta_t)**(1.0_lkind/3.0_lkind) + x_q = (1.0_lkind - 16.0_lkind*zeta_q)**(1.0_lkind/3.0_lkind) + + psi_t = ln_z_zt - 1.5_lkind*log((x**2+x+1.0_lkind)/(x_t**2 + x_t + 1.0_lkind)) + s3 * & + (atan((2.0_lkind*x+1.0_lkind)/s3) - atan((2.0_lkind*x_t + 1.0_lkind)/s3)) + psi_q = ln_z_zq - 1.5_lkind*log((x**2+x+1.0_lkind)/(x_q**2 + x_q + 1.0_lkind)) + s3 * & + (atan((2.0_lkind*x+1.0_lkind)/s3) - atan((2.0_lkind*x_q + 1.0_lkind)/s3)) end where else where(unstable) - x = sqrt(1 - 16.0*zeta) - x_t = sqrt(1 - 16.0*zeta_t) - x_q = sqrt(1 - 16.0*zeta_q) + x = sqrt(1.0_lkind - 16.0_lkind*zeta) + x_t = sqrt(1.0_lkind - 16.0_lkind*zeta_t) + x_q = sqrt(1.0_lkind - 16.0_lkind*zeta_q) - psi_t = ln_z_zt - 2.0*log( (1.0 + x)/(1.0 + x_t) ) - psi_q = ln_z_zq - 2.0*log( (1.0 + x)/(1.0 + x_q) ) + psi_t = ln_z_zt - 2.0_lkind*log( (1.0_lkind + x)/(1.0_lkind + x_t) ) + psi_q = ln_z_zq - 2.0_lkind*log( (1.0_lkind + x)/(1.0_lkind + x_q) ) end where end if @@ -637,38 +626,38 @@ if( stable_option == 1) then where (stable) - psi_t = ln_z_zt + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_t)) & + psi_t = ln_z_zt + (5.0_lkind - b_stab)*log((1.0_lkind + zeta)/(1.0_lkind + zeta_t)) & + b_stab*(zeta - zeta_t) - psi_q = ln_z_zq + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_q)) & + psi_q = ln_z_zq + (5.0_lkind - b_stab)*log((1.0_lkind + zeta)/(1.0_lkind + zeta_q)) & + b_stab*(zeta - zeta_q) end where else if (stable_option == 2) then - lambda = 1.0 + (5.0 - b_stab)*zeta_trans + lambda = 1.0_lkind + (5.0_lkind - b_stab)*zeta_trans weakly_stable = stable .and. zeta <= zeta_trans strongly_stable = stable .and. zeta > zeta_trans where (weakly_stable) - psi_t = ln_z_zt + 5.0*(zeta - zeta_t) - psi_q = ln_z_zq + 5.0*(zeta - zeta_q) + psi_t = ln_z_zt + 5.0_lkind*(zeta - zeta_t) + psi_q = ln_z_zq + 5.0_lkind*(zeta - zeta_q) end where where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) + x = (lambda - 1.0_lkind)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) endwhere where (strongly_stable .and. zeta_t <= zeta_trans) - psi_t = ln_z_zt + x + 5.0*(zeta_trans - zeta_t) + psi_t = ln_z_zt + x + 5.0_lkind*(zeta_trans - zeta_t) end where where (strongly_stable .and. zeta_t > zeta_trans) psi_t = lambda*ln_z_zt + b_stab*(zeta - zeta_t) endwhere where (strongly_stable .and. zeta_q <= zeta_trans) - psi_q = ln_z_zq + x + 5.0*(zeta_trans - zeta_q) + psi_q = ln_z_zq + x + 5.0_lkind*(zeta_trans - zeta_q) end where where (strongly_stable .and. zeta_q > zeta_trans) psi_q = lambda*ln_z_zq + b_stab*(zeta - zeta_q) @@ -676,58 +665,58 @@ else if (stable_option == 2) then end if -end subroutine monin_obukhov_integral_tq +end subroutine MONIN_OBUKHOV_INTEGRAL_TQ_ -pure subroutine monin_obukhov_stable_mix(stable_option, rich_crit, zeta_trans, & +pure subroutine MONIN_OBUKHOV_STABLE_MIX_(stable_option, rich_crit, zeta_trans, & & n, rich, mix, ier) - integer, intent(in ) :: stable_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(in ), dimension(n) :: rich - real , intent( out), dimension(n) :: mix - integer, intent( out) :: ier + integer, intent(in) :: stable_option + real(kind=FMS_MO_KIND_), intent(in) :: rich_crit, zeta_trans + integer, intent(in) :: n + real(kind=FMS_MO_KIND_), intent(in), dimension(n) :: rich + real(kind=FMS_MO_KIND_), intent(out), dimension(n) :: mix + integer, intent(out) :: ier - real :: r, a, b, c, zeta, phi - real :: b_stab, rich_trans, lambda - integer :: i + real(kind=FMS_MO_KIND_) :: r, a, b, c, zeta, phi + real(kind=FMS_MO_KIND_) :: b_stab, rich_trans, lambda + integer :: i + integer, parameter :: lkind = FMS_MO_KIND_ ier = 0 -mix = 0.0 -b_stab = 1.0/rich_crit -rich_trans = zeta_trans/(1.0 + 5.0*zeta_trans) +mix = 0.0_lkind +b_stab = 1.0_lkind/rich_crit +rich_trans = zeta_trans/(1.0_lkind + 5.0_lkind*zeta_trans) if(stable_option == 1) then - c = - 1.0 + c = - 1.0_lkind do i = 1, n - if(rich(i) > 0.0 .and. rich(i) < rich_crit) then - r = 1.0/rich(i) - a = r - b_stab - b = r - (1.0 + 5.0) - zeta = (-b + sqrt(b*b - 4.0*a*c))/(2.0*a) - phi = 1.0 + b_stab*zeta + (5.0 - b_stab)*zeta/(1.0 + zeta) - mix(i) = 1./(phi*phi) + if(rich(i) > 0.0_lkind .and. rich(i) < rich_crit) then + r = 1.0_lkind/rich(i) + a = r - b_stab + b = r - (1.0_lkind + 5.0_lkind) + zeta = (-b + sqrt(b*b - 4.0_lkind*a*c))/(2.0_lkind*a) + phi = 1.0_lkind + b_stab*zeta + (5.0_lkind - b_stab)*zeta/(1.0_lkind + zeta) + mix(i) = 1.0_lkind/(phi*phi) endif end do else if(stable_option == 2) then - lambda = 1.0 + (5.0 - b_stab)*zeta_trans + lambda = 1.0_lkind + (5.0_lkind - b_stab)*zeta_trans - where(rich > 0.0 .and. rich <= rich_trans) - mix = (1.0 - 5.0*rich)**2 + where(rich > 0.0_lkind .and. rich <= rich_trans) + mix = (1.0_lkind - 5.0_lkind*rich)**2 end where where(rich > rich_trans .and. rich < rich_crit) - mix = ((1.0 - b_stab*rich)/lambda)**2 + mix = ((1.0_lkind - b_stab*rich)/lambda)**2 end where end if -end subroutine monin_obukhov_stable_mix +end subroutine MONIN_OBUKHOV_STABLE_MIX_ -end module monin_obukhov_inter !> @} ! close documentation grouping diff --git a/monin_obukhov/include/monin_obukhov_inter_r4.fh b/monin_obukhov/include/monin_obukhov_inter_r4.fh new file mode 100644 index 0000000000..0039ee4a95 --- /dev/null +++ b/monin_obukhov/include/monin_obukhov_inter_r4.fh @@ -0,0 +1,59 @@ +!*********************************************************************** +!* GNU Lesser General Public License +!* +!* This file is part of the GFDL Flexible Modeling System (FMS). +!* +!* FMS is free software: you can redistribute it and/or modify it under +!* the terms of the GNU Lesser General Public License as published by +!* the Free Software Foundation, either version 3 of the License, or (at +!* your option) any later version. +!* +!* FMS is distributed in the hope that it will be useful, but WITHOUT +!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +!* for more details. +!* +!* You should have received a copy of the GNU Lesser General Public +!* License along with FMS. If not, see . +!*********************************************************************** +!> @defgroup monin_obukhov_inter monin_obukhov_inter +!> @ingroup monin_obukhov +!> @brief Utility routines to be used in @ref monin_obukhov_mod + +!> @addtogroup monin_obukhov_inter +!> @{ + +#undef FMS_MO_KIND_ +#define FMS_MO_KIND_ r4_kind + +#undef MONIN_OBUKHOV_DIFF_ +#define MONIN_OBUKHOV_DIFF_ monin_obukhov_diff_r4 + +#undef MONIN_OBUKHOV_DRAG_1D_ +#define MONIN_OBUKHOV_DRAG_1D_ monin_obukhov_drag_1d_r4 + +#undef MONIN_OBUKHOV_SOLVE_ZETA_ +#define MONIN_OBUKHOV_SOLVE_ZETA_ monin_obukhov_solve_zeta_r4 + +#undef MONIN_OBUKHOV_DERIVATIVE_T_ +#define MONIN_OBUKHOV_DERIVATIVE_T_ monin_obukhov_derivative_t_r4 + +#undef MONIN_OBUKHOV_DERIVATIVE_M_ +#define MONIN_OBUKHOV_DERIVATIVE_M_ monin_obukhov_derivative_m_r4 + +#undef MONIN_OBUKHOV_PROFILE_1D_ +#define MONIN_OBUKHOV_PROFILE_1D_ monin_obukhov_profile_1d_r4 + +#undef MONIN_OBUKHOV_INTEGRAL_M_ +#define MONIN_OBUKHOV_INTEGRAL_M_ monin_obukhov_integral_m_r4 + +#undef MONIN_OBUKHOV_INTEGRAL_TQ_ +#define MONIN_OBUKHOV_INTEGRAL_TQ_ monin_obukhov_integral_tq_r4 + +#undef MONIN_OBUKHOV_STABLE_MIX_ +#define MONIN_OBUKHOV_STABLE_MIX_ monin_obukhov_stable_mix_r4 + +#include "monin_obukhov_inter.inc" + +!> @} +! close documentation grouping \ No newline at end of file diff --git a/monin_obukhov/include/monin_obukhov_inter_r8.fh b/monin_obukhov/include/monin_obukhov_inter_r8.fh new file mode 100644 index 0000000000..caeabdf42b --- /dev/null +++ b/monin_obukhov/include/monin_obukhov_inter_r8.fh @@ -0,0 +1,59 @@ +!*********************************************************************** +!* GNU Lesser General Public License +!* +!* This file is part of the GFDL Flexible Modeling System (FMS). +!* +!* FMS is free software: you can redistribute it and/or modify it under +!* the terms of the GNU Lesser General Public License as published by +!* the Free Software Foundation, either version 3 of the License, or (at +!* your option) any later version. +!* +!* FMS is distributed in the hope that it will be useful, but WITHOUT +!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +!* for more details. +!* +!* You should have received a copy of the GNU Lesser General Public +!* License along with FMS. If not, see . +!*********************************************************************** +!> @defgroup monin_obukhov_inter monin_obukhov_inter +!> @ingroup monin_obukhov +!> @brief Utility routines to be used in @ref monin_obukhov_mod + +!> @addtogroup monin_obukhov_inter +!> @{ + +#undef FMS_MO_KIND_ +#define FMS_MO_KIND_ r8_kind + +#undef MONIN_OBUKHOV_DIFF_ +#define MONIN_OBUKHOV_DIFF_ monin_obukhov_diff_r8 + +#undef MONIN_OBUKHOV_DRAG_1D_ +#define MONIN_OBUKHOV_DRAG_1D_ monin_obukhov_drag_1d_r8 + +#undef MONIN_OBUKHOV_SOLVE_ZETA_ +#define MONIN_OBUKHOV_SOLVE_ZETA_ monin_obukhov_solve_zeta_r8 + +#undef MONIN_OBUKHOV_DERIVATIVE_T_ +#define MONIN_OBUKHOV_DERIVATIVE_T_ monin_obukhov_derivative_t_r8 + +#undef MONIN_OBUKHOV_DERIVATIVE_M_ +#define MONIN_OBUKHOV_DERIVATIVE_M_ monin_obukhov_derivative_m_r8 + +#undef MONIN_OBUKHOV_PROFILE_1D_ +#define MONIN_OBUKHOV_PROFILE_1D_ monin_obukhov_profile_1d_r8 + +#undef MONIN_OBUKHOV_INTEGRAL_M_ +#define MONIN_OBUKHOV_INTEGRAL_M_ monin_obukhov_integral_m_r8 + +#undef MONIN_OBUKHOV_INTEGRAL_TQ_ +#define MONIN_OBUKHOV_INTEGRAL_TQ_ monin_obukhov_integral_tq_r8 + +#undef MONIN_OBUKHOV_STABLE_MIX_ +#define MONIN_OBUKHOV_STABLE_MIX_ monin_obukhov_stable_mix_r8 + +#include "monin_obukhov_inter.inc" + +!> @} +! close documentation grouping \ No newline at end of file diff --git a/monin_obukhov/include/monin_obukhov_r4.fh b/monin_obukhov/include/monin_obukhov_r4.fh new file mode 100644 index 0000000000..354708a76b --- /dev/null +++ b/monin_obukhov/include/monin_obukhov_r4.fh @@ -0,0 +1,108 @@ +! -*-f90-*- + +!*********************************************************************** +!* GNU Lesser General Public License +!* +!* This file is part of the GFDL Flexible Modeling System (FMS). +!* +!* FMS is free software: you can redistribute it and/or modify it under +!* the terms of the GNU Lesser General Public License as published by +!* the Free Software Foundation, either version 3 of the License, or (at +!* your option) any later version. +!* +!* FMS is distributed in the hope that it will be useful, but WITHOUT +!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +!* for more details. +!* +!* You should have received a copy of the GNU Lesser General Public +!* License along with FMS. If not, see . +!*********************************************************************** +!> @defgroup monin_obukhov_mod monin_obukhov_mod +!> @ingroup monin_obukhov +!> @brief Routines for computing surface drag coefficients +!! from data at the lowest model level +!! and for computing the profile of fields +!! between the lowest model level and the ground +!! using Monin-Obukhov scaling + +!> @{ + +#undef FMS_MO_KIND_ +#define FMS_MO_KIND_ r4_kind +#undef MO_DRAG_1D_ +#define MO_DRAG_1D_ mo_drag_1d_r4 + +#undef MO_PROFILE_1D_ +#define MO_PROFILE_1D_ mo_profile_1d_r4 + +#undef STABLE_MIX_3D_ +#define STABLE_MIX_3D_ stable_mix_3d_r4 + +#undef MO_DIFF_2D_N_ +#define MO_DIFF_2D_N_ mo_diff_2d_n_r4 + +#undef SOLVE_ZETA_ +#define SOLVE_ZETA_ solve_zeta_r4 + +#undef MO_DERIVATIVE_M_ +#define MO_DERIVATIVE_M_ mo_derivative_m_r4 + +#undef MO_DERIVATIVE_T_ +#define MO_DERIVATIVE_T_ mo_derivative_t_r4 + +#undef MO_INTEGRAL_TQ_ +#define MO_INTEGRAL_TQ_ mo_integral_tq_r4 + +#undef MO_INTEGRAL_M_ +#define MO_INTEGRAL_M_ mo_integral_m_r4 + +#undef MO_DRAG_2D_ +#define MO_DRAG_2D_ mo_drag_2d_r4 + +#undef MO_DRAG_0D_ +#define MO_DRAG_0D_ mo_drag_0d_r4 + +#undef MO_PROFILE_2D_ +#define MO_PROFILE_2D_ mo_profile_2d_r4 + +#undef MO_PROFILE_0D_ +#define MO_PROFILE_0D_ mo_profile_0d_r4 + +#undef MO_PROFILE_1D_N_ +#define MO_PROFILE_1D_N_ mo_profile_1d_n_r4 + +#undef MO_PROFILE_0D_N_ +#define MO_PROFILE_0D_N_ mo_profile_0d_n_r4 + +#undef MO_PROFILE_2D_N_ +#define MO_PROFILE_2D_N_ mo_profile_2d_n_r4 + +#undef MO_DIFF_2D_1_ +#define MO_DIFF_2D_1_ mo_diff_2d_1_r4 + +#undef MO_DIFF_1D_1_ +#define MO_DIFF_1D_1_ mo_diff_1d_1_r4 + +#undef MO_DIFF_1D_N_ +#define MO_DIFF_1D_N_ mo_diff_1d_n_r4 + +#undef MO_DIFF_0D_1_ +#define MO_DIFF_0D_1_ mo_diff_0d_1_r4 + +#undef MO_DIFF_0D_N_ +#define MO_DIFF_0D_N_ mo_diff_0d_n_r4 + +#undef STABLE_MIX_2D_ +#define STABLE_MIX_2D_ stable_mix_2d_r4 + +#undef STABLE_MIX_1D_ +#define STABLE_MIX_1D_ stable_mix_1d_r4 + +#undef STABLE_MIX_0D_ +#define STABLE_MIX_0D_ stable_mix_0d_r4 + +#include "monin_obukhov.inc" + +!> @} +! close documentation grouping \ No newline at end of file diff --git a/monin_obukhov/include/monin_obukhov_r8.fh b/monin_obukhov/include/monin_obukhov_r8.fh new file mode 100644 index 0000000000..2ac76f6300 --- /dev/null +++ b/monin_obukhov/include/monin_obukhov_r8.fh @@ -0,0 +1,112 @@ +! -*-f90-*- + +!*********************************************************************** +!* GNU Lesser General Public License +!* +!* This file is part of the GFDL Flexible Modeling System (FMS). +!* +!* FMS is free software: you can redistribute it and/or modify it under +!* the terms of the GNU Lesser General Public License as published by +!* the Free Software Foundation, either version 3 of the License, or (at +!* your option) any later version. +!* +!* FMS is distributed in the hope that it will be useful, but WITHOUT +!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +!* for more details. +!* +!* You should have received a copy of the GNU Lesser General Public +!* License along with FMS. If not, see . +!*********************************************************************** +!> @defgroup monin_obukhov_mod monin_obukhov_mod +!> @ingroup monin_obukhov +!> @brief Routines for computing surface drag coefficients +!! from data at the lowest model level +!! and for computing the profile of fields +!! between the lowest model level and the ground +!! using Monin-Obukhov scaling + +!> @{ + +#undef FMS_MO_KIND_ +#define FMS_MO_KIND_ r8_kind + +#undef MONIN_OBUKHOV_INIT_ +#define MONIN_OBUKHOV_INIT_ monin_obukhov_init_r8 + +#undef MO_DRAG_1D_ +#define MO_DRAG_1D_ mo_drag_1d_r8 + +#undef MO_PROFILE_1D_ +#define MO_PROFILE_1D_ mo_profile_1d_r8 + +#undef STABLE_MIX_3D_ +#define STABLE_MIX_3D_ stable_mix_3d_r8 + +#undef MO_DIFF_2D_N_ +#define MO_DIFF_2D_N_ mo_diff_2d_n_r8 + +#undef SOLVE_ZETA_ +#define SOLVE_ZETA_ solve_zeta_r8 + +#undef MO_DERIVATIVE_M_ +#define MO_DERIVATIVE_M_ mo_derivative_m_r8 + +#undef MO_DERIVATIVE_T_ +#define MO_DERIVATIVE_T_ mo_derivative_t_r8 + +#undef MO_INTEGRAL_TQ_ +#define MO_INTEGRAL_TQ_ mo_integral_tq_r8 + +#undef MO_INTEGRAL_M_ +#define MO_INTEGRAL_M_ mo_integral_m_r8 + +#undef MO_DRAG_2D_ +#define MO_DRAG_2D_ mo_drag_2d_r8 + +#undef MO_DRAG_0D_ +#define MO_DRAG_0D_ mo_drag_0d_r8 + +#undef MO_PROFILE_2D_ +#define MO_PROFILE_2D_ mo_profile_2d_r8 + +#undef MO_PROFILE_0D_ +#define MO_PROFILE_0D_ mo_profile_0d_r8 + +#undef MO_PROFILE_1D_N_ +#define MO_PROFILE_1D_N_ mo_profile_1d_n_r8 + +#undef MO_PROFILE_0D_N_ +#define MO_PROFILE_0D_N_ mo_profile_0d_n_r8 + +#undef MO_PROFILE_2D_N_ +#define MO_PROFILE_2D_N_ mo_profile_2d_n_r8 + +#undef MO_DIFF_2D_1_ +#define MO_DIFF_2D_1_ mo_diff_2d_1_r8 + +#undef MO_DIFF_1D_1_ +#define MO_DIFF_1D_1_ mo_diff_1d_1_r8 + +#undef MO_DIFF_1D_N_ +#define MO_DIFF_1D_N_ mo_diff_1d_n_r8 + +#undef MO_DIFF_0D_1_ +#define MO_DIFF_0D_1_ mo_diff_0d_1_r8 + +#undef MO_DIFF_0D_N_ +#define MO_DIFF_0D_N_ mo_diff_0d_n_r8 + +#undef STABLE_MIX_2D_ +#define STABLE_MIX_2D_ stable_mix_2d_r8 + +#undef STABLE_MIX_1D_ +#define STABLE_MIX_1D_ stable_mix_1d_r8 + +#undef STABLE_MIX_0D_ +#define STABLE_MIX_0D_ stable_mix_0d_r8 + +#include "monin_obukhov.inc" + +!> @} +! close documentation grouping \ No newline at end of file diff --git a/monin_obukhov/monin_obukhov.F90 b/monin_obukhov/monin_obukhov.F90 index ac8a89075f..257889ff62 100644 --- a/monin_obukhov/monin_obukhov.F90 +++ b/monin_obukhov/monin_obukhov.F90 @@ -33,6 +33,7 @@ module monin_obukhov_mod write_version_number use monin_obukhov_inter, only: monin_obukhov_diff, monin_obukhov_drag_1d, & monin_obukhov_profile_1d, monin_obukhov_stable_mix +use platform_mod, only: r4_kind, r8_kind implicit none private @@ -48,29 +49,55 @@ module monin_obukhov_mod !> @brief Compute surface drag coefficients !> @ingroup monin_obukhov_mod interface mo_drag - module procedure mo_drag_0d, mo_drag_1d, mo_drag_2d + module procedure mo_drag_0d_r4, mo_drag_0d_r8 + module procedure mo_drag_1d_r4, mo_drag_1d_r8 + module procedure mo_drag_2d_r4, mo_drag_2d_r8 end interface !> @ingroup monin_obukhov_mod interface mo_profile - module procedure mo_profile_0d, mo_profile_1d, mo_profile_2d, & - mo_profile_0d_n, mo_profile_1d_n, mo_profile_2d_n + module procedure mo_profile_0d_r4, mo_profile_0d_r8 + module procedure mo_profile_1d_r4, mo_profile_1d_r8 + module procedure mo_profile_2d_r4, mo_profile_2d_r8 + module procedure mo_profile_0d_n_r4, mo_profile_0d_n_r8 + module procedure mo_profile_1d_n_r4, mo_profile_1d_n_r8 + module procedure mo_profile_2d_n_r4, mo_profile_2d_n_r8 end interface !> @ingroup monin_obukhov_mod interface mo_diff - module procedure mo_diff_0d_n, mo_diff_0d_1, & - mo_diff_1d_n, mo_diff_1d_1, & - mo_diff_2d_n, mo_diff_2d_1 + module procedure mo_diff_0d_n_r4, mo_diff_0d_n_r8 + module procedure mo_diff_0d_1_r4, mo_diff_0d_1_r8 + module procedure mo_diff_1d_n_r4, mo_diff_1d_n_r8 + module procedure mo_diff_1d_1_r4, mo_diff_1d_1_r8 + module procedure mo_diff_2d_n_r4, mo_diff_2d_n_r8 + module procedure mo_diff_2d_1_r4, mo_diff_2d_1_r8 end interface !> @ingroup monin_obukhov_mod interface stable_mix - module procedure stable_mix_0d, stable_mix_1d, & - stable_mix_2d, stable_mix_3d + module procedure stable_mix_0d_r4, stable_mix_0d_r8 + module procedure stable_mix_1d_r4, stable_mix_1d_r8 + module procedure stable_mix_2d_r4, stable_mix_2d_r8 + module procedure stable_mix_3d_r4, stable_mix_3d_r8 end interface +interface mo_integral_m + module procedure mo_integral_m_r4, mo_integral_m_r8 +end interface mo_integral_m + +interface mo_integral_tq + module procedure mo_integral_tq_r4, mo_integral_tq_r8 +end interface mo_integral_tq + +interface mo_derivative_m + module procedure mo_derivative_m_r4, mo_derivative_m_r8 +end interface mo_derivative_m + +interface mo_derivative_t + module procedure mo_derivative_t_r4, mo_derivative_t_r8 +end interface mo_derivative_t !> @addtogroup monin_obukhov_mod !> @{ @@ -83,14 +110,14 @@ module monin_obukhov_mod ! DEFAULT VALUES OF NAMELIST PARAMETERS: -real :: rich_crit = 2.0 -real :: drag_min_heat = 1.e-05 -real :: drag_min_moist = 1.e-05 -real :: drag_min_mom = 1.e-05 -logical :: neutral = .false. -integer :: stable_option = 1 -real :: zeta_trans = 0.5 -logical :: new_mo_option = .false. +real(kind=r8_kind) :: rich_crit = 2.0_r8_kind +real(kind=r8_kind) :: drag_min_heat = 1.0E-05_r8_kind +real(kind=r8_kind) :: drag_min_moist = 1.0E-05_r8_kind +real(kind=r8_kind) :: drag_min_mom = 1.0E-05_r8_kind +logical :: neutral = .false. +integer :: stable_option = 1 +real(kind=r8_kind) :: zeta_trans = 0.5_r8_kind +logical :: new_mo_option = .false. namelist /monin_obukhov_nml/ rich_crit, neutral, drag_min_heat, & @@ -101,10 +128,10 @@ module monin_obukhov_mod ! MODULE VARIABLES -real, parameter :: small = 1.e-04 -real :: b_stab, r_crit, lambda, rich_trans -real :: sqrt_drag_min_heat, sqrt_drag_min_moist, sqrt_drag_min_mom -logical :: module_is_initialized = .false. +real(kind=r8_kind), parameter :: small = 1.0E-04_r8_kind +real(kind=r8_kind) :: b_stab, r_crit, lambda, rich_trans +real(kind=r8_kind) :: sqrt_drag_min_heat, sqrt_drag_min_moist, sqrt_drag_min_mom +logical :: module_is_initialized = .false. contains @@ -130,19 +157,19 @@ subroutine monin_obukhov_init !---------------------------------------------------------------------- -if(rich_crit.le.0.25) call error_mesg( & +if(rich_crit.le.0.25_r8_kind) call error_mesg( & 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & 'rich_crit in monin_obukhov_mod must be > 0.25', FATAL) -if(drag_min_heat.le.0.0) call error_mesg( & +if(drag_min_heat.le.0.0_r8_kind) call error_mesg( & 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & 'drag_min_heat in monin_obukhov_mod must be >= 0.0', FATAL) -if(drag_min_moist.le.0.0) call error_mesg( & +if(drag_min_moist.le.0.0_r8_kind) call error_mesg( & 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & 'drag_min_moist in monin_obukhov_mod must be >= 0.0', FATAL) -if(drag_min_mom.le.0.0) call error_mesg( & +if(drag_min_mom.le.0.0_r8_kind) call error_mesg( & 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & 'drag_min_mom in monin_obukhov_mod must be >= 0.0', FATAL) @@ -154,21 +181,21 @@ subroutine monin_obukhov_init 'MONIN_OBUKHOV_INIT in MONIN_OBUKHOV_MOD', & 'zeta_trans must be positive', FATAL) -b_stab = 1.0/rich_crit -r_crit = 0.95*rich_crit ! convergence can get slow if one is +b_stab = 1.0_r8_kind/rich_crit +r_crit = 0.95_r8_kind*rich_crit ! convergence can get slow if one is ! close to rich_crit -sqrt_drag_min_heat = 0.0 -if(drag_min_heat.ne.0.0) sqrt_drag_min_heat = sqrt(drag_min_heat) +sqrt_drag_min_heat = 0.0_r8_kind +if(drag_min_heat.ne.0.0_r8_kind) sqrt_drag_min_heat = sqrt(drag_min_heat) -sqrt_drag_min_moist = 0.0 -if(drag_min_moist.ne.0.0) sqrt_drag_min_moist = sqrt(drag_min_moist) +sqrt_drag_min_moist = 0.0_r8_kind +if(drag_min_moist.ne.0.0_r8_kind) sqrt_drag_min_moist = sqrt(drag_min_moist) -sqrt_drag_min_mom = 0.0 -if(drag_min_mom.ne.0.0) sqrt_drag_min_mom = sqrt(drag_min_mom) +sqrt_drag_min_mom = 0.0_r8_kind +if(drag_min_mom.ne.0.0_r8_kind) sqrt_drag_min_mom = sqrt(drag_min_mom) -lambda = 1.0 + (5.0 - b_stab)*zeta_trans ! used only if stable_option = 2 -rich_trans = zeta_trans/(1.0 + 5.0*zeta_trans) ! used only if stable_option = 2 +lambda = 1.0_r8_kind + (5.0_r8_kind - b_stab)*zeta_trans ! used only if stable_option = 2 +rich_trans = zeta_trans/(1.0_r8_kind + 5.0_r8_kind*zeta_trans) ! used only if stable_option = 2 module_is_initialized = .true. @@ -185,812 +212,8 @@ end subroutine monin_obukhov_end !======================================================================= -subroutine mo_drag_1d & - (pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, drag_q, & - u_star, b_star, avail) - -real, intent(in) , dimension(:) :: pt, pt0, z, z0, zt, zq, speed -real, intent(inout), dimension(:) :: drag_m, drag_t, drag_q, u_star, b_star -logical, intent(in), optional, dimension(:) :: avail - -logical :: lavail, avail_dummy(1) -integer :: n, ier - -integer, parameter :: max_iter = 20 -real , parameter :: error=1.e-04, zeta_min=1.e-06, small=1.e-04 - -! #include "monin_obukhov_interfaces.h" - -if(.not.module_is_initialized) call error_mesg('mo_drag_1d in monin_obukhov_mod', & - 'monin_obukhov_init has not been called', FATAL) - -n = size(pt) -lavail = .false. -if(present(avail)) lavail = .true. - - -if(lavail) then - if (count(avail) .eq. 0) return - call monin_obukhov_drag_1d(grav, vonkarm, & - & error, zeta_min, max_iter, small, & - & neutral, stable_option, new_mo_option, rich_crit, zeta_trans, &!miz - & drag_min_heat, drag_min_moist, drag_min_mom, & - & n, pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, & - & drag_q, u_star, b_star, lavail, avail, ier) -else - call monin_obukhov_drag_1d(grav, vonkarm, & - & error, zeta_min, max_iter, small, & - & neutral, stable_option, new_mo_option, rich_crit, zeta_trans, &!miz - & drag_min_heat, drag_min_moist, drag_min_mom, & - & n, pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, & - & drag_q, u_star, b_star, lavail, avail_dummy, ier) -endif - -end subroutine mo_drag_1d - - -!======================================================================= - -subroutine mo_profile_1d(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - del_m, del_t, del_q, avail) - -real, intent(in) :: zref, zref_t -real, intent(in) , dimension(:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:) :: del_m, del_t, del_q -logical, intent(in) , optional, dimension(:) :: avail - -logical :: dummy_avail(1) -integer :: n, ier - -! #include "monin_obukhov_interfaces.h" - -if(.not.module_is_initialized) call error_mesg('mo_profile_1d in monin_obukhov_mod', & - 'monin_obukhov_init has not been called', FATAL) - -n = size(z) -if(present(avail)) then - - if (count(avail) .eq. 0) return - - call monin_obukhov_profile_1d(vonkarm, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, & - & n, zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - & del_m, del_t, del_q, .true., avail, ier) - -else - - call monin_obukhov_profile_1d(vonkarm, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, & - & n, zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - & del_m, del_t, del_q, .false., dummy_avail, ier) - -endif - -end subroutine mo_profile_1d - -!======================================================================= - -subroutine stable_mix_3d(rich, mix) - -real, intent(in) , dimension(:,:,:) :: rich -real, intent(out), dimension(:,:,:) :: mix -integer :: n2 !< Size of dimension 2 of mix and rich -integer :: n3 !< Size of dimension 3 of mix and rich -integer :: i, j !< Loop indices - -n2 = size(mix, 2) -n3 = size(mix, 3) - -do j=1, n3 - do i=1, n2 - call stable_mix(rich(:, i, j), mix(:, i, j)) - enddo -enddo - -end subroutine stable_mix_3d - -!======================================================================= - -subroutine mo_diff_2d_n(z, u_star, b_star, k_m, k_h) - -real, intent(in), dimension(:,:,:) :: z -real, intent(in), dimension(:,:) :: u_star, b_star -real, intent(out), dimension(:,:,:) :: k_m, k_h - -integer :: ni, nj, nk, ier -real, parameter :: ustar_min = 1.e-10 - -if(.not.module_is_initialized) call error_mesg('mo_diff_2d_n in monin_obukhov_mod', & - 'monin_obukhov_init has not been called', FATAL) - -ni = size(z, 1); nj = size(z, 2); nk = size(z, 3) -call monin_obukhov_diff(vonkarm, & - & ustar_min, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, & - & ni, nj, nk, z, u_star, b_star, k_m, k_h, ier) - -end subroutine mo_diff_2d_n - -!======================================================================= -! The following routines are used by the public interfaces above -!======================================================================= - -subroutine solve_zeta(rich, z, z0, zt, zq, f_m, f_t, f_q, mask) - -real , intent(in) , dimension(:) :: rich, z, z0, zt, zq -logical, intent(in) , dimension(:) :: mask -real , intent(out), dimension(:) :: f_m, f_t, f_q - - -real, parameter :: error = 1.e-04 -real, parameter :: zeta_min = 1.e-06 -integer, parameter :: max_iter = 20 - -real :: max_cor -integer :: iter - -real, dimension(size(rich(:))) :: & - d_rich, rich_1, correction, corr, z_z0, z_zt, z_zq, & - ln_z_z0, ln_z_zt, ln_z_zq, zeta, & - phi_m, phi_m_0, phi_t, phi_t_0, rzeta, & - zeta_0, zeta_t, zeta_q, df_m, df_t - -logical, dimension(size(rich(:))) :: mask_1 - - -z_z0 = z/z0 -z_zt = z/zt -z_zq = z/zq -ln_z_z0 = log(z_z0) -ln_z_zt = log(z_zt) -ln_z_zq = log(z_zq) - -corr = 0.0 -mask_1 = mask - -! initial guess - -where(mask_1) - zeta = rich*ln_z_z0*ln_z_z0/ln_z_zt -elsewhere - zeta = 0.0 -end where - -where (mask_1 .and. rich >= 0.0) - zeta = zeta/(1.0 - rich/rich_crit) -end where - -iter_loop: do iter = 1, max_iter - - where (mask_1 .and. abs(zeta).lt.zeta_min) - zeta = 0.0 - f_m = ln_z_z0 - f_t = ln_z_zt - f_q = ln_z_zq - mask_1 = .false. ! don't do any more calculations at these pts - end where - - where (mask_1) - rzeta = 1.0/zeta - zeta_0 = zeta/z_z0 - zeta_t = zeta/z_zt - zeta_q = zeta/z_zq - elsewhere - zeta_0 = 0.0 - zeta_t = 0.0 - zeta_q = 0.0 - end where - - call mo_derivative_m(phi_m , zeta , mask_1) - call mo_derivative_m(phi_m_0, zeta_0, mask_1) - call mo_derivative_t(phi_t , zeta , mask_1) - call mo_derivative_t(phi_t_0, zeta_t, mask_1) - - call mo_integral_m(f_m, zeta, zeta_0, ln_z_z0, mask_1) - call mo_integral_tq(f_t, f_q, zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq, mask_1) - - where (mask_1) - df_m = (phi_m - phi_m_0)*rzeta - df_t = (phi_t - phi_t_0)*rzeta - rich_1 = zeta*f_t/(f_m*f_m) - d_rich = rich_1*( rzeta + df_t/f_t - 2.0 *df_m/f_m) - correction = (rich - rich_1)/d_rich - corr = min(abs(correction),abs(correction/zeta)) - ! the criterion corr < error seems to work ok, but is a bit arbitrary - ! when zeta is small the tolerance is reduced - end where - - max_cor= maxval(corr) - - if(max_cor > error) then - mask_1 = mask_1 .and. (corr > error) - ! change the mask so computation proceeds only on non-converged points - where(mask_1) - zeta = zeta + correction - end where - cycle iter_loop - else - return - end if - -end do iter_loop - -call error_mesg ('solve_zeta in monin_obukhov_mod', & - 'surface drag iteration did not converge', FATAL) - -end subroutine solve_zeta - -!======================================================================= - -subroutine mo_derivative_m(phi_m, zeta, mask) - -! the differential similarity function for momentum - -real , intent(out), dimension(:) :: phi_m -real , intent(in), dimension(:) :: zeta -logical , intent(in), dimension(:) :: mask - -logical, dimension(size(zeta(:))) :: stable, unstable -real , dimension(size(zeta(:))) :: x - -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 - -where (unstable) - x = (1 - 16.0*zeta )**(-0.5) - phi_m = sqrt(x) ! phi_m = (1 - 16.0*zeta)**(-0.25) -end where - -if(stable_option == 1) then - - where (stable) - phi_m = 1.0 + zeta *(5.0 + b_stab*zeta)/(1.0 + zeta) - end where - -else if(stable_option == 2) then - - where (stable .and. zeta < zeta_trans) - phi_m = 1 + 5.0*zeta - end where - where (stable .and. zeta >= zeta_trans) - phi_m = lambda + b_stab*zeta - end where - -endif - -return -end subroutine mo_derivative_m - -!======================================================================= - -subroutine mo_derivative_t(phi_t, zeta, mask) - -! the differential similarity function for buoyancy and tracers - -real , intent(out), dimension(:) :: phi_t -real , intent(in), dimension(:) :: zeta -logical , intent(in), dimension(:) :: mask - -logical, dimension(size(zeta(:))) :: stable, unstable - -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 - -where (unstable) - phi_t = (1 - 16.0*zeta)**(-0.5) -end where - -if(stable_option == 1) then - - where (stable) - phi_t = 1.0 + zeta*(5.0 + b_stab*zeta)/(1.0 + zeta) - end where - -else if(stable_option == 2) then - - where (stable .and. zeta < zeta_trans) - phi_t = 1 + 5.0*zeta - end where - where (stable .and. zeta >= zeta_trans) - phi_t = lambda + b_stab*zeta - end where - -endif - -return -end subroutine mo_derivative_t - -!======================================================================= - -subroutine mo_integral_tq (psi_t, psi_q, zeta, zeta_t, zeta_q, & - ln_z_zt, ln_z_zq, mask) - -! the integral similarity function for moisture and tracers - -real , intent(out), dimension(:) :: psi_t, psi_q -real , intent(in), dimension(:) :: zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq -logical , intent(in), dimension(:) :: mask - -real, dimension(size(zeta(:))) :: x, x_t, x_q - -logical, dimension(size(zeta(:))) :: stable, unstable, & - weakly_stable, strongly_stable - -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 - -where(unstable) - - x = sqrt(1 - 16.0*zeta) - x_t = sqrt(1 - 16.0*zeta_t) - x_q = sqrt(1 - 16.0*zeta_q) - - psi_t = ln_z_zt - 2.0*log( (1.0 + x)/(1.0 + x_t) ) - psi_q = ln_z_zq - 2.0*log( (1.0 + x)/(1.0 + x_q) ) - -end where - -if( stable_option == 1) then - - where (stable) - - psi_t = ln_z_zt + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_t)) & - + b_stab*(zeta - zeta_t) - psi_q = ln_z_zq + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_q)) & - + b_stab*(zeta - zeta_q) - - end where - -else if (stable_option == 2) then - - weakly_stable = stable .and. zeta <= zeta_trans - strongly_stable = stable .and. zeta > zeta_trans - - where (weakly_stable) - psi_t = ln_z_zt + 5.0*(zeta - zeta_t) - psi_q = ln_z_zq + 5.0*(zeta - zeta_q) - end where - - where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) - endwhere - - where (strongly_stable .and. zeta_t <= zeta_trans) - psi_t = ln_z_zt + x + 5.0*(zeta_trans - zeta_t) - end where - where (strongly_stable .and. zeta_t > zeta_trans) - psi_t = lambda*ln_z_zt + b_stab*(zeta - zeta_t) - endwhere - - where (strongly_stable .and. zeta_q <= zeta_trans) - psi_q = ln_z_zq + x + 5.0*(zeta_trans - zeta_q) - end where - where (strongly_stable .and. zeta_q > zeta_trans) - psi_q = lambda*ln_z_zq + b_stab*(zeta - zeta_q) - endwhere - -end if - -return -end subroutine mo_integral_tq - -!======================================================================= - -subroutine mo_integral_m (psi_m, zeta, zeta_0, ln_z_z0, mask) - -! the integral similarity function for momentum - -real , intent(out), dimension(:) :: psi_m -real , intent(in), dimension(:) :: zeta, zeta_0, ln_z_z0 -logical , intent(in), dimension(:) :: mask - -real, dimension(size(zeta(:))) :: x, x_0, x1, x1_0, num, denom, y - -logical, dimension(size(zeta(:))) :: stable, unstable, & - weakly_stable, strongly_stable - -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 - -where(unstable) - - x = sqrt(1 - 16.0*zeta) - x_0 = sqrt(1 - 16.0*zeta_0) - - x = sqrt(x) - x_0 = sqrt(x_0) - - x1 = 1.0 + x - x1_0 = 1.0 + x_0 - - num = x1*x1*(1.0 + x*x) - denom = x1_0*x1_0*(1.0 + x_0*x_0) - y = atan(x) - atan(x_0) - psi_m = ln_z_z0 - log(num/denom) + 2*y - -end where - -if( stable_option == 1) then - - where (stable) - psi_m = ln_z_z0 + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_0)) & - + b_stab*(zeta - zeta_0) - end where - -else if (stable_option == 2) then - - weakly_stable = stable .and. zeta <= zeta_trans - strongly_stable = stable .and. zeta > zeta_trans - - where (weakly_stable) - psi_m = ln_z_z0 + 5.0*(zeta - zeta_0) - end where - - where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) - endwhere - - where (strongly_stable .and. zeta_0 <= zeta_trans) - psi_m = ln_z_z0 + x + 5.0*(zeta_trans - zeta_0) - end where - where (strongly_stable .and. zeta_0 > zeta_trans) - psi_m = lambda*ln_z_z0 + b_stab*(zeta - zeta_0) - endwhere - -end if - -return -end subroutine mo_integral_m - - -!======================================================================= -! The following routines allow the public interfaces to be used -! with different dimensions of the input and output -! -!======================================================================= - - -subroutine mo_drag_2d & - (pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, drag_q, u_star, b_star) - -real, intent(in) , dimension(:,:) :: z, speed, pt, pt0, z0, zt, zq -real, intent(out) , dimension(:,:) :: drag_m, drag_t, drag_q -real, intent(inout), dimension(:,:) :: u_star, b_star - -integer :: j - -do j = 1, size(pt,2) - call mo_drag_1d (pt(:,j), pt0(:,j), z(:,j), z0(:,j), zt(:,j), zq(:,j), & - speed(:,j), drag_m(:,j), drag_t(:,j), drag_q(:,j), & - u_star(:,j), b_star(:,j)) -end do - - -return -end subroutine mo_drag_2d - -!======================================================================= -subroutine mo_drag_0d & - (pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, drag_q, u_star, b_star) - -real, intent(in) :: z, speed, pt, pt0, z0, zt, zq -real, intent(out) :: drag_m, drag_t, drag_q, u_star, b_star - -real, dimension(1) :: pt_1, pt0_1, z_1, z0_1, zt_1, zq_1, speed_1, & - drag_m_1, drag_t_1, drag_q_1, u_star_1, b_star_1 - -pt_1 (1) = pt -pt0_1 (1) = pt0 -z_1 (1) = z -z0_1 (1) = z0 -zt_1 (1) = zt -zq_1 (1) = zq -speed_1(1) = speed - -call mo_drag_1d (pt_1, pt0_1, z_1, z0_1, zt_1, zq_1, speed_1, & - drag_m_1, drag_t_1, drag_q_1, u_star_1, b_star_1) - -drag_m = drag_m_1(1) -drag_t = drag_t_1(1) -drag_q = drag_q_1(1) -u_star = u_star_1(1) -b_star = b_star_1(1) - -return -end subroutine mo_drag_0d -!======================================================================= - -subroutine mo_profile_2d(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - del_m, del_h, del_q) - -real, intent(in) :: zref, zref_t -real, intent(in) , dimension(:,:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:,:) :: del_m, del_h, del_q - -integer :: j - -do j = 1, size(z,2) - call mo_profile_1d (zref, zref_t, z(:,j), z0(:,j), zt(:,j), & - zq(:,j), u_star(:,j), b_star(:,j), q_star(:,j), & - del_m(:,j), del_h (:,j), del_q (:,j)) -enddo - -return -end subroutine mo_profile_2d - -!======================================================================= - -subroutine mo_profile_0d(zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - del_m, del_h, del_q) - -real, intent(in) :: zref, zref_t -real, intent(in) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out) :: del_m, del_h, del_q - -real, dimension(1) :: z_1, z0_1, zt_1, zq_1, u_star_1, b_star_1, q_star_1, & - del_m_1, del_h_1, del_q_1 - -z_1 (1) = z -z0_1 (1) = z0 -zt_1 (1) = zt -zq_1 (1) = zq -u_star_1(1) = u_star -b_star_1(1) = b_star -q_star_1(1) = q_star - -call mo_profile_1d (zref, zref_t, z_1, z0_1, zt_1, zq_1, & - u_star_1, b_star_1, q_star_1, & - del_m_1, del_h_1, del_q_1) - -del_m = del_m_1(1) -del_h = del_h_1(1) -del_q = del_q_1(1) - - -return -end subroutine mo_profile_0d - -!======================================================================= - -subroutine mo_profile_1d_n(zref, z, z0, zt, zq, u_star, b_star, q_star, & - del_m, del_t, del_q, avail) - -real, intent(in), dimension(:) :: zref -real, intent(in) , dimension(:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:,:) :: del_m, del_t, del_q -logical, intent(in) , optional, dimension(:) :: avail - -integer :: k - -do k = 1, size(zref(:)) - if(present(avail)) then - call mo_profile_1d (zref(k), zref(k), z, z0, zt, zq, & - u_star, b_star, q_star, del_m(:,k), del_t(:,k), del_q(:,k), avail) - else - call mo_profile_1d (zref(k), zref(k), z, z0, zt, zq, & - u_star, b_star, q_star, del_m(:,k), del_t(:,k), del_q(:,k)) - endif -enddo - -return -end subroutine mo_profile_1d_n - -!======================================================================= - -subroutine mo_profile_0d_n(zref, z, z0, zt, zq, u_star, b_star, q_star, & - del_m, del_t, del_q) - -real, intent(in), dimension(:) :: zref -real, intent(in) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:) :: del_m, del_t, del_q - -integer :: k - -do k = 1, size(zref(:)) - call mo_profile_0d (zref(k), zref(k), z, z0, zt, zq, & - u_star, b_star, q_star, del_m(k), del_t(k), del_q(k)) -enddo - -return -end subroutine mo_profile_0d_n - -!======================================================================= - -subroutine mo_profile_2d_n(zref, z, z0, zt, zq, u_star, b_star, q_star, & - del_m, del_t, del_q) - -real, intent(in), dimension(:) :: zref -real, intent(in), dimension(:,:) :: z, z0, zt, zq, u_star, b_star, q_star -real, intent(out), dimension(:,:,:) :: del_m, del_t, del_q - -integer :: k - -do k = 1, size(zref(:)) - call mo_profile_2d (zref(k), zref(k), z, z0, zt, zq, & - u_star, b_star, q_star, del_m(:,:,k), del_t(:,:,k), del_q(:,:,k)) -enddo - -return -end subroutine mo_profile_2d_n - -!======================================================================= - -subroutine mo_diff_2d_1(z, u_star, b_star, k_m, k_h) - -real, intent(in), dimension(:,:) :: z, u_star, b_star -real, intent(out), dimension(:,:) :: k_m, k_h - -real , dimension(size(z,1),size(z,2),1) :: z_n, k_m_n, k_h_n - -z_n(:,:,1) = z - -call mo_diff_2d_n(z_n, u_star, b_star, k_m_n, k_h_n) - -k_m = k_m_n(:,:,1) -k_h = k_h_n(:,:,1) - -return -end subroutine mo_diff_2d_1 - - -!======================================================================= - -subroutine mo_diff_1d_1(z, u_star, b_star, k_m, k_h) - -real, intent(in), dimension(:) :: z, u_star, b_star -real, intent(out), dimension(:) :: k_m, k_h - -real, dimension(size(z),1,1) :: z_n, k_m_n, k_h_n -real, dimension(size(z),1) :: u_star_n, b_star_n - -z_n (:,1,1) = z -u_star_n(:,1) = u_star -b_star_n(:,1) = b_star - -call mo_diff_2d_n(z_n, u_star_n, b_star_n, k_m_n, k_h_n) - -k_m = k_m_n(:,1,1) -k_h = k_h_n(:,1,1) - -return -end subroutine mo_diff_1d_1 - -!======================================================================= - -subroutine mo_diff_1d_n(z, u_star, b_star, k_m, k_h) - -real, intent(in), dimension(:,:) :: z -real, intent(in), dimension(:) :: u_star, b_star -real, intent(out), dimension(:,:) :: k_m, k_h - -real, dimension(size(z,1),1) :: u_star2, b_star2 -real, dimension(size(z,1),1, size(z,2)) :: z2, k_m2, k_h2 - -integer :: n - -do n = 1, size(z,2) - z2 (:,1,n) = z(:,n) -enddo -u_star2(:,1) = u_star -b_star2(:,1) = b_star - -call mo_diff_2d_n(z2, u_star2, b_star2, k_m2, k_h2) - -do n = 1, size(z,2) - k_m(:,n) = k_m2(:,1,n) - k_h(:,n) = k_h2(:,1,n) -enddo - -return -end subroutine mo_diff_1d_n - -!======================================================================= - -subroutine mo_diff_0d_1(z, u_star, b_star, k_m, k_h) - -real, intent(in) :: z, u_star, b_star -real, intent(out) :: k_m, k_h - -integer :: ni, nj, nk, ier -real, parameter :: ustar_min = 1.e-10 -real, dimension(1,1,1) :: z_a, k_m_a, k_h_a -real, dimension(1,1) :: u_star_a, b_star_a - -if(.not.module_is_initialized) call error_mesg('mo_diff_0d_1 in monin_obukhov_mod', & - 'monin_obukhov_init has not been called', FATAL) - -ni = 1; nj = 1; nk = 1 -z_a(1,1,1) = z -u_star_a(1,1) = u_star -b_star_a(1,1) = b_star -call monin_obukhov_diff(vonkarm, & - & ustar_min, & - & neutral, stable_option, new_mo_option,rich_crit, zeta_trans, &!miz - & ni, nj, nk, z_a, u_star_a, b_star_a, k_m_a, k_h_a, ier) -k_m = k_m_a(1,1,1) -k_h = k_h_a(1,1,1) -end subroutine mo_diff_0d_1 - -!======================================================================= - -subroutine mo_diff_0d_n(z, u_star, b_star, k_m, k_h) - -real, intent(in), dimension(:) :: z -real, intent(in) :: u_star, b_star -real, intent(out), dimension(:) :: k_m, k_h - -integer :: ni, nj, nk, ier -real, parameter :: ustar_min = 1.e-10 -real, dimension(1,1,size(z)) :: z_a, k_m_a, k_h_a -real, dimension(1,1) :: u_star_a, b_star_a - -if(.not.module_is_initialized) call error_mesg('mo_diff_0d_n in monin_obukhov_mod', & - 'monin_obukhov_init has not been called', FATAL) - -ni = 1; nj = 1; nk = size(z(:)) -z_a(1,1,:) = z(:) -u_star_a(1,1) = u_star -b_star_a(1,1) = b_star -call monin_obukhov_diff(vonkarm, & - & ustar_min, & - & neutral, stable_option,new_mo_option,rich_crit, zeta_trans, &!miz - & ni, nj, nk, z_a, u_star_a, b_star_a, k_m_a, k_h_a, ier) -k_m(:) = k_m_a(1,1,:) -k_h(:) = k_h_a(1,1,:) -end subroutine mo_diff_0d_n - -!======================================================================= - -subroutine stable_mix_2d(rich, mix) - -real, intent(in) , dimension(:,:) :: rich -real, intent(out), dimension(:,:) :: mix -integer :: n2 !< Size of dimension 2 of mix and rich -integer :: i !< Loop index - -n2 = size(mix, 2) - -do i=1, n2 - call stable_mix(rich(:, i), mix(:, i)) -enddo - -end subroutine stable_mix_2d - - -!======================================================================= - -subroutine stable_mix_1d(rich, mix) - -real, intent(in) , dimension(:) :: rich -real, intent(out), dimension(:) :: mix -integer :: n !< Size of mix and rich -integer :: ierr !< Error code set by monin_obukhov_stable_mix - -if (.not.module_is_initialized) call error_mesg('stable_mix in monin_obukhov_mod', & - 'monin_obukhov_init has not been called', FATAL) - -n = size(mix) - -call monin_obukhov_stable_mix(stable_option, rich_crit, zeta_trans, & - & n, rich, mix, ierr) - -end subroutine stable_mix_1d - -!======================================================================= - -subroutine stable_mix_0d(rich, mix) - -real, intent(in) :: rich -real, intent(out) :: mix - -real, dimension(1) :: mix_1d !< Representation of mix as a dimension(1) array - -call stable_mix([rich], mix_1d) - -mix = mix_1d(1) - -end subroutine stable_mix_0d -!======================================================================= +#include "monin_obukhov_r4.fh" +#include "monin_obukhov_r8.fh" end module monin_obukhov_mod !> @} diff --git a/monin_obukhov/monin_obukhov_inter.F90 b/monin_obukhov/monin_obukhov_inter.F90 index 9aa43e8a0e..a4af79c314 100644 --- a/monin_obukhov/monin_obukhov_inter.F90 +++ b/monin_obukhov/monin_obukhov_inter.F90 @@ -23,6 +23,8 @@ !> @addtogroup monin_obukhov_inter !> @{ module monin_obukhov_inter + +use platform_mod, only: r4_kind, r8_kind implicit none private @@ -37,696 +39,46 @@ module monin_obukhov_inter public :: monin_obukhov_integral_tq public :: monin_obukhov_stable_mix +interface monin_obukhov_diff + module procedure monin_obukhov_diff_r4, monin_obukhov_diff_r8 +end interface monin_obukhov_diff -contains - - -pure subroutine monin_obukhov_diff(vonkarm, & - & ustar_min, & - & neutral, stable_option,new_mo_option,rich_crit, zeta_trans, & - & ni, nj, nk, z, u_star, b_star, k_m, k_h, ier) - - real , intent(in ) :: vonkarm - real , intent(in ) :: ustar_min !< = 1.e-10 - logical, intent(in ) :: neutral - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option !miz - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: ni, nj, nk - real , intent(in ), dimension(ni, nj, nk) :: z - real , intent(in ), dimension(ni, nj) :: u_star, b_star - real , intent( out), dimension(ni, nj, nk) :: k_m, k_h - integer, intent( out) :: ier - - real , dimension(ni, nj) :: phi_m, phi_h, zeta, uss - integer :: j, k - logical, dimension(ni) :: mask - - ier = 0 - - mask = .true. - uss = max(u_star, ustar_min) - - if(neutral) then - do k = 1, size(z,3) - k_m(:,:,k) = vonkarm *uss*z(:,:,k) - k_h(:,:,k) = k_m(:,:,k) - end do - else - do k = 1, size(z,3) - zeta = - vonkarm * b_star*z(:,:,k)/(uss*uss) - do j = 1, size(z,2) - call monin_obukhov_derivative_m(stable_option, rich_crit, zeta_trans, & - & ni, phi_m(:,j), zeta(:,j), mask, ier) - call monin_obukhov_derivative_t(stable_option, new_mo_option,rich_crit, zeta_trans, & - & ni, phi_h(:,j), zeta(:,j), mask, ier) - enddo - k_m(:,:,k) = vonkarm * uss*z(:,:,k)/phi_m - k_h(:,:,k) = vonkarm * uss*z(:,:,k)/phi_h - end do - endif - -end subroutine monin_obukhov_diff - - -pure subroutine monin_obukhov_drag_1d(grav, vonkarm, & - & error, zeta_min, max_iter, small, & - & neutral, stable_option, new_mo_option, rich_crit, zeta_trans,& - & drag_min_heat, drag_min_moist, drag_min_mom, & - & n, pt, pt0, z, z0, zt, zq, speed, drag_m, drag_t, & - & drag_q, u_star, b_star, lavail, avail, ier) - - real , intent(in ) :: grav - real , intent(in ) :: vonkarm - real , intent(in ) :: error !< = 1.e-04 - real , intent(in ) :: zeta_min !< = 1.e-06 - integer, intent(in ) :: max_iter !< = 20 - real , intent(in ) :: small !< = 1.e-04 - logical, intent(in ) :: neutral - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option - real , intent(in ) :: rich_crit, zeta_trans - real , intent(in ) :: drag_min_heat, drag_min_moist, drag_min_mom - integer, intent(in ) :: n - real , intent(in ), dimension(n) :: pt, pt0, z, z0, zt, zq, speed - real , intent(inout), dimension(n) :: drag_m, drag_t, drag_q, u_star, b_star - logical, intent(in ) :: lavail !< whether to use provided mask or not - logical, intent(in ), dimension(n) :: avail !< provided mask - integer, intent(out ) :: ier - - real , dimension(n) :: rich, fm, ft, fq, zz - logical, dimension(n) :: mask, mask_1, mask_2 - real , dimension(n) :: delta_b !!, us, bs, qs - real :: r_crit, sqrt_drag_min_heat - real :: sqrt_drag_min_moist, sqrt_drag_min_mom - real :: us, bs, qs - integer :: i - - ier = 0 - r_crit = 0.95*rich_crit ! convergence can get slow if one is - ! close to rich_crit - sqrt_drag_min_heat = 0.0 - if(drag_min_heat.ne.0.0) sqrt_drag_min_heat = sqrt(drag_min_heat) - sqrt_drag_min_moist = 0.0 - if(drag_min_moist.ne.0.0) sqrt_drag_min_moist = sqrt(drag_min_moist) - sqrt_drag_min_mom = 0.0 - if(drag_min_mom.ne.0.0) sqrt_drag_min_mom = sqrt(drag_min_mom) - - mask = .true. - if(lavail) mask = avail - - where(mask) - delta_b = grav*(pt0 - pt)/pt0 - rich = - z*delta_b/(speed*speed + small) - zz = max(z,z0,zt,zq) - elsewhere - rich = 0.0 - end where - - if(neutral) then - - do i = 1, n - if(mask(i)) then - fm(i) = log(zz(i)/z0(i)) - ft(i) = log(zz(i)/zt(i)) - fq(i) = log(zz(i)/zq(i)) - us = vonkarm/fm(i) - bs = vonkarm/ft(i) - qs = vonkarm/fq(i) - drag_m(i) = us*us - drag_t(i) = us*bs - drag_q(i) = us*qs - u_star(i) = us*speed(i) - b_star(i) = bs*delta_b(i) - end if - enddo - - else - - mask_1 = mask .and. rich < r_crit - mask_2 = mask .and. rich >= r_crit - - do i = 1, n - if(mask_2(i)) then - drag_m(i) = drag_min_mom - drag_t(i) = drag_min_heat - drag_q(i) = drag_min_moist - us = sqrt_drag_min_mom - bs = sqrt_drag_min_heat - u_star(i) = us*speed(i) - b_star(i) = bs*delta_b(i) - end if - enddo - - call monin_obukhov_solve_zeta (error, zeta_min, max_iter, small, & - & stable_option, new_mo_option, rich_crit, zeta_trans, & - & n, rich, zz, z0, zt, zq, fm, ft, fq, mask_1, ier) - - do i = 1, n - if(mask_1(i)) then - us = max(vonkarm/fm(i), sqrt_drag_min_mom) - bs = max(vonkarm/ft(i), sqrt_drag_min_heat) - qs = max(vonkarm/fq(i), sqrt_drag_min_moist) - drag_m(i) = us*us - drag_t(i) = us*bs - drag_q(i) = us*qs - u_star(i) = us*speed(i) - b_star(i) = bs*delta_b(i) - endif - enddo - - end if - -end subroutine monin_obukhov_drag_1d - - -pure subroutine monin_obukhov_solve_zeta(error, zeta_min, max_iter, small, & - & stable_option, new_mo_option, rich_crit, zeta_trans, & !miz - & n, rich, z, z0, zt, zq, f_m, f_t, f_q, mask, ier) - - real , intent(in ) :: error !< = 1.e-04 - real , intent(in ) :: zeta_min !< = 1.e-06 - integer, intent(in ) :: max_iter !< = 20 - real , intent(in ) :: small !< = 1.e-04 - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(in ), dimension(n) :: rich, z, z0, zt, zq - logical, intent(in ), dimension(n) :: mask - real , intent( out), dimension(n) :: f_m, f_t, f_q - integer, intent( out) :: ier - - real :: max_cor - integer :: iter - real, dimension(n) :: & - d_rich, rich_1, correction, corr, z_z0, z_zt, z_zq, & - ln_z_z0, ln_z_zt, ln_z_zq, zeta, & - phi_m, phi_m_0, phi_t, phi_t_0, rzeta, & - zeta_0, zeta_t, zeta_q, df_m, df_t - logical, dimension(n) :: mask_1 - - ier = 0 - - z_z0 = z/z0 - z_zt = z/zt - z_zq = z/zq - ln_z_z0 = log(z_z0) - ln_z_zt = log(z_zt) - ln_z_zq = log(z_zq) - - corr = 0.0 - mask_1 = mask - - ! initial guess - - zeta = 0.0 - where(mask_1) - zeta = rich*ln_z_z0*ln_z_z0/ln_z_zt - end where - - where (mask_1 .and. rich >= 0.0) - zeta = zeta/(1.0 - rich/rich_crit) - end where - - iter_loop: do iter = 1, max_iter - - where (mask_1 .and. abs(zeta).lt.zeta_min) - zeta = 0.0 - f_m = ln_z_z0 - f_t = ln_z_zt - f_q = ln_z_zq - mask_1 = .false. ! don't do any more calculations at these pts - end where - - - zeta_0 = 0.0 - zeta_t = 0.0 - zeta_q = 0.0 - where (mask_1) - rzeta = 1.0/zeta - zeta_0 = zeta/z_z0 - zeta_t = zeta/z_zt - zeta_q = zeta/z_zq - end where - - call monin_obukhov_derivative_m(stable_option, rich_crit, zeta_trans, & - & n, phi_m , zeta , mask_1, ier) - call monin_obukhov_derivative_m(stable_option, rich_crit, zeta_trans, & - & n, phi_m_0, zeta_0, mask_1, ier) - call monin_obukhov_derivative_t(stable_option, new_mo_option,rich_crit, zeta_trans, & - & n, phi_t , zeta , mask_1, ier) - call monin_obukhov_derivative_t(stable_option, new_mo_option,rich_crit, zeta_trans, & - & n, phi_t_0, zeta_t, mask_1, ier) - - call monin_obukhov_integral_m(stable_option, rich_crit, zeta_trans, & - & n, f_m, zeta, zeta_0, ln_z_z0, mask_1, ier) - call monin_obukhov_integral_tq(stable_option, new_mo_option, rich_crit, zeta_trans, & - & n, f_t, f_q, zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq, mask_1, ier) - - where (mask_1) - df_m = (phi_m - phi_m_0)*rzeta - df_t = (phi_t - phi_t_0)*rzeta - rich_1 = zeta*f_t/(f_m*f_m) - d_rich = rich_1*( rzeta + df_t/f_t - 2.0 *df_m/f_m) - correction = (rich - rich_1)/d_rich - corr = min(abs(correction),abs(correction/zeta)) - ! the criterion corr < error seems to work ok, but is a bit arbitrary - ! when zeta is small the tolerance is reduced - end where - - max_cor= maxval(corr) - - if(max_cor > error) then - mask_1 = mask_1 .and. (corr > error) - ! change the mask so computation proceeds only on non-converged points - where(mask_1) - zeta = zeta + correction - end where - cycle iter_loop - else - return - end if - - end do iter_loop - - ier = 1 ! surface drag iteration did not converge - -end subroutine monin_obukhov_solve_zeta - - -!> The differential similarity function for buoyancy and tracers -! seems to be the same as monin_obukhov_derivative_m? -pure subroutine monin_obukhov_derivative_t(stable_option,new_mo_option,rich_crit, zeta_trans, & - & n, phi_t, zeta, mask, ier) - - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option !miz - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent( out), dimension(n) :: phi_t - real , intent(in ), dimension(n) :: zeta - logical, intent(in ), dimension(n) :: mask - integer, intent( out) :: ier - - logical, dimension(n) :: stable, unstable - real :: b_stab, lambda - - ier = 0 - b_stab = 1.0/rich_crit - - stable = mask .and. zeta >= 0.0 - unstable = mask .and. zeta < 0.0 - -!miz: modified to include new monin-obukhov option - if (new_mo_option) then - where (unstable) - phi_t = (1 - 16.0*zeta)**(-1./3.) - end where - else - where (unstable) - phi_t = (1 - 16.0*zeta)**(-0.5) - end where - end if -!miz - - if(stable_option == 1) then - - where (stable) - phi_t = 1.0 + zeta*(5.0 + b_stab*zeta)/(1.0 + zeta) - end where - - else if(stable_option == 2) then - - lambda = 1.0 + (5.0 - b_stab)*zeta_trans - - where (stable .and. zeta < zeta_trans) - phi_t = 1 + 5.0*zeta - end where - where (stable .and. zeta >= zeta_trans) - phi_t = lambda + b_stab*zeta - end where - - endif - -end subroutine monin_obukhov_derivative_t - - -! the differential similarity function for momentum -pure subroutine monin_obukhov_derivative_m(stable_option, rich_crit, zeta_trans, & - & n, phi_m, zeta, mask, ier) - - integer, intent(in ) :: stable_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent( out), dimension(n) :: phi_m - real , intent(in ), dimension(n) :: zeta - logical, intent(in ), dimension(n) :: mask - integer, intent(out ) :: ier - - logical, dimension(n) :: stable, unstable - real , dimension(n) :: x - real :: b_stab, lambda - - ier = 0 - b_stab = 1.0/rich_crit - - stable = mask .and. zeta >= 0.0 - unstable = mask .and. zeta < 0.0 - - where (unstable) - x = (1 - 16.0*zeta )**(-0.5) - phi_m = sqrt(x) ! phi_m = (1 - 16.0*zeta)**(-0.25) - end where - - if(stable_option == 1) then - - where (stable) - phi_m = 1.0 + zeta *(5.0 + b_stab*zeta)/(1.0 + zeta) - end where - - else if(stable_option == 2) then - - lambda = 1.0 + (5.0 - b_stab)*zeta_trans - - where (stable .and. zeta < zeta_trans) - phi_m = 1 + 5.0*zeta - end where - where (stable .and. zeta >= zeta_trans) - phi_m = lambda + b_stab*zeta - end where +interface monin_obukhov_drag_1d + module procedure monin_obukhov_drag_1d_r4, monin_obukhov_drag_1d_r8 +end interface monin_obukhov_drag_1d - endif +interface monin_obukhov_solve_zeta + module procedure monin_obukhov_solve_zeta_r4, monin_obukhov_solve_zeta_r8 +end interface monin_obukhov_solve_zeta -end subroutine monin_obukhov_derivative_m +interface monin_obukhov_derivative_t + module procedure monin_obukhov_derivative_t_r4, monin_obukhov_derivative_t_r8 +end interface monin_obukhov_derivative_t +interface monin_obukhov_derivative_m + module procedure monin_obukhov_derivative_m_r4, monin_obukhov_derivative_m_r8 +end interface monin_obukhov_derivative_m -pure subroutine monin_obukhov_profile_1d(vonkarm, & - & neutral, stable_option, new_mo_option, rich_crit, zeta_trans, & - & n, zref, zref_t, z, z0, zt, zq, u_star, b_star, q_star, & - & del_m, del_t, del_q, lavail, avail, ier) +interface monin_obukhov_profile_1d + module procedure monin_obukhov_profile_1d_r4, monin_obukhov_profile_1d_r8 +end interface monin_obukhov_profile_1d - real , intent(in ) :: vonkarm - logical, intent(in ) :: neutral - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real, intent(in ) :: zref, zref_t - real, intent(in ), dimension(n) :: z, z0, zt, zq, u_star, b_star, q_star - real, intent( out), dimension(n) :: del_m, del_t, del_q - logical, intent(in ) :: lavail !< whether to use provided mask or not - logical, intent(in ), dimension(n) :: avail !< provided mask - integer, intent(out ) :: ier +interface monin_obukhov_integral_m + module procedure monin_obukhov_integral_m_r4, monin_obukhov_integral_m_r8 +end interface monin_obukhov_integral_m - real, dimension(n) :: zeta, zeta_0, zeta_t, zeta_q, zeta_ref, zeta_ref_t, & - ln_z_z0, ln_z_zt, ln_z_zq, ln_z_zref, ln_z_zref_t, & - f_m_ref, f_m, f_t_ref, f_t, f_q_ref, f_q, & - mo_length_inv - logical, dimension(n) :: mask +interface monin_obukhov_integral_tq + module procedure monin_obukhov_integral_tq_r4, monin_obukhov_integral_tq_r8 +end interface monin_obukhov_integral_tq - ier = 0 +interface monin_obukhov_stable_mix + module procedure monin_obukhov_stable_mix_r4, monin_obukhov_stable_mix_r8 +end interface monin_obukhov_stable_mix - mask = .true. - if(lavail) mask = avail - - del_m = 0.0 ! zero output arrays - del_t = 0.0 - del_q = 0.0 - - where(mask) - ln_z_z0 = log(z/z0) - ln_z_zt = log(z/zt) - ln_z_zq = log(z/zq) - ln_z_zref = log(z/zref) - ln_z_zref_t = log(z/zref_t) - endwhere - - if(neutral) then - - where(mask) - del_m = 1.0 - ln_z_zref /ln_z_z0 - del_t = 1.0 - ln_z_zref_t/ln_z_zt - del_q = 1.0 - ln_z_zref_t/ln_z_zq - endwhere - - else - - where(mask .and. u_star > 0.0) - mo_length_inv = - vonkarm * b_star/(u_star*u_star) - zeta = z *mo_length_inv - zeta_0 = z0 *mo_length_inv - zeta_t = zt *mo_length_inv - zeta_q = zq *mo_length_inv - zeta_ref = zref *mo_length_inv - zeta_ref_t = zref_t*mo_length_inv - endwhere - - call monin_obukhov_integral_m(stable_option, rich_crit, zeta_trans, & - & n, f_m, zeta, zeta_0, ln_z_z0, mask, ier) - call monin_obukhov_integral_m(stable_option, rich_crit, zeta_trans, & - & n, f_m_ref, zeta, zeta_ref, ln_z_zref, mask, ier) - - call monin_obukhov_integral_tq(stable_option, new_mo_option, rich_crit, zeta_trans, & - & n, f_t, f_q, zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq, mask, ier) - call monin_obukhov_integral_tq(stable_option, new_mo_option, rich_crit, zeta_trans, & - & n, f_t_ref, f_q_ref, zeta, zeta_ref_t, zeta_ref_t, ln_z_zref_t, ln_z_zref_t, mask, ier) - - where(mask) - del_m = 1.0 - f_m_ref/f_m - del_t = 1.0 - f_t_ref/f_t - del_q = 1.0 - f_q_ref/f_q - endwhere - - end if - - -end subroutine monin_obukhov_profile_1d - - -!> The integral similarity function for momentum -pure subroutine monin_obukhov_integral_m(stable_option, rich_crit, zeta_trans, & - & n, psi_m, zeta, zeta_0, ln_z_z0, mask, ier) - - integer, intent(in ) :: stable_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(inout), dimension(n) :: psi_m - real , intent(in) , dimension(n) :: zeta, zeta_0, ln_z_z0 - logical, intent(in) , dimension(n) :: mask - integer, intent(out) :: ier - - real :: b_stab, lambda - real, dimension(n) :: x, x_0, x1, x1_0, num, denom, y - logical, dimension(n) :: stable, unstable, & - weakly_stable, strongly_stable - - ier = 0 - - b_stab = 1.0/rich_crit - - stable = mask .and. zeta >= 0.0 - unstable = mask .and. zeta < 0.0 - - where(unstable) - - x = sqrt(1 - 16.0*zeta) - x_0 = sqrt(1 - 16.0*zeta_0) - - x = sqrt(x) - x_0 = sqrt(x_0) - - x1 = 1.0 + x - x1_0 = 1.0 + x_0 - - num = x1*x1*(1.0 + x*x) - denom = x1_0*x1_0*(1.0 + x_0*x_0) - y = atan(x) - atan(x_0) - psi_m = ln_z_z0 - log(num/denom) + 2*y - - end where - - if( stable_option == 1) then - - where (stable) - psi_m = ln_z_z0 + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_0)) & - + b_stab*(zeta - zeta_0) - end where - - else if (stable_option == 2) then - - lambda = 1.0 + (5.0 - b_stab)*zeta_trans - - weakly_stable = stable .and. zeta <= zeta_trans - strongly_stable = stable .and. zeta > zeta_trans - - where (weakly_stable) - psi_m = ln_z_z0 + 5.0*(zeta - zeta_0) - end where - - where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) - endwhere - - where (strongly_stable .and. zeta_0 <= zeta_trans) - psi_m = ln_z_z0 + x + 5.0*(zeta_trans - zeta_0) - end where - where (strongly_stable .and. zeta_0 > zeta_trans) - psi_m = lambda*ln_z_z0 + b_stab*(zeta - zeta_0) - endwhere - - end if - -end subroutine monin_obukhov_integral_m - - -!> The integral similarity function for moisture and tracers -pure subroutine monin_obukhov_integral_tq(stable_option, new_mo_option, rich_crit, zeta_trans, & - & n, psi_t, psi_q, zeta, zeta_t, zeta_q, & - & ln_z_zt, ln_z_zq, mask, ier) - - integer, intent(in ) :: stable_option - logical, intent(in ) :: new_mo_option !miz - real, intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(inout), dimension(n) :: psi_t, psi_q - real , intent(in) , dimension(n) :: zeta, zeta_t, zeta_q, ln_z_zt, ln_z_zq - logical, intent(in) , dimension(n) :: mask - integer, intent( out) :: ier - - real, dimension(n) :: x, x_t, x_q - logical, dimension(n) :: stable, unstable, & - weakly_stable, strongly_stable - real :: b_stab, lambda - real :: s3 !miz - - ier = 0 - - b_stab = 1.0/rich_crit - -stable = mask .and. zeta >= 0.0 -unstable = mask .and. zeta < 0.0 - -!miz: modified to include a new monin-obukhov option -if (new_mo_option) then - s3 = sqrt(3.0) - where(unstable) - x = (1 - 16.0*zeta)**(1./3.) - x_t = (1 - 16.0*zeta_t)**(1./3.) - x_q = (1 - 16.0*zeta_q)**(1./3.) - - psi_t = ln_z_zt - 1.5*log((x**2+x+1)/(x_t**2 + x_t + 1)) + s3*(atan((2*x+1)/s3) - atan((2*x_t + 1)/s3)) - psi_q = ln_z_zq - 1.5*log((x**2+x+1)/(x_q**2 + x_q + 1)) + s3*(atan((2*x+1)/s3) - atan((2*x_q + 1)/s3)) - end where -else - -where(unstable) - - x = sqrt(1 - 16.0*zeta) - x_t = sqrt(1 - 16.0*zeta_t) - x_q = sqrt(1 - 16.0*zeta_q) - - psi_t = ln_z_zt - 2.0*log( (1.0 + x)/(1.0 + x_t) ) - psi_q = ln_z_zq - 2.0*log( (1.0 + x)/(1.0 + x_q) ) - -end where -end if -!miz - -if( stable_option == 1) then - - where (stable) - - psi_t = ln_z_zt + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_t)) & - + b_stab*(zeta - zeta_t) - psi_q = ln_z_zq + (5.0 - b_stab)*log((1.0 + zeta)/(1.0 + zeta_q)) & - + b_stab*(zeta - zeta_q) - - end where - -else if (stable_option == 2) then - - lambda = 1.0 + (5.0 - b_stab)*zeta_trans - - weakly_stable = stable .and. zeta <= zeta_trans - strongly_stable = stable .and. zeta > zeta_trans - - where (weakly_stable) - psi_t = ln_z_zt + 5.0*(zeta - zeta_t) - psi_q = ln_z_zq + 5.0*(zeta - zeta_q) - end where - - where(strongly_stable) - x = (lambda - 1.0)*log(zeta/zeta_trans) + b_stab*(zeta - zeta_trans) - endwhere - - where (strongly_stable .and. zeta_t <= zeta_trans) - psi_t = ln_z_zt + x + 5.0*(zeta_trans - zeta_t) - end where - where (strongly_stable .and. zeta_t > zeta_trans) - psi_t = lambda*ln_z_zt + b_stab*(zeta - zeta_t) - endwhere - - where (strongly_stable .and. zeta_q <= zeta_trans) - psi_q = ln_z_zq + x + 5.0*(zeta_trans - zeta_q) - end where - where (strongly_stable .and. zeta_q > zeta_trans) - psi_q = lambda*ln_z_zq + b_stab*(zeta - zeta_q) - endwhere - -end if - -end subroutine monin_obukhov_integral_tq - - -pure subroutine monin_obukhov_stable_mix(stable_option, rich_crit, zeta_trans, & - & n, rich, mix, ier) - - integer, intent(in ) :: stable_option - real , intent(in ) :: rich_crit, zeta_trans - integer, intent(in ) :: n - real , intent(in ), dimension(n) :: rich - real , intent( out), dimension(n) :: mix - integer, intent( out) :: ier - - real :: r, a, b, c, zeta, phi - real :: b_stab, rich_trans, lambda - integer :: i - - ier = 0 - -mix = 0.0 -b_stab = 1.0/rich_crit -rich_trans = zeta_trans/(1.0 + 5.0*zeta_trans) - -if(stable_option == 1) then - - c = - 1.0 - do i = 1, n - if(rich(i) > 0.0 .and. rich(i) < rich_crit) then - r = 1.0/rich(i) - a = r - b_stab - b = r - (1.0 + 5.0) - zeta = (-b + sqrt(b*b - 4.0*a*c))/(2.0*a) - phi = 1.0 + b_stab*zeta + (5.0 - b_stab)*zeta/(1.0 + zeta) - mix(i) = 1./(phi*phi) - endif - end do - -else if(stable_option == 2) then - - lambda = 1.0 + (5.0 - b_stab)*zeta_trans - - where(rich > 0.0 .and. rich <= rich_trans) - mix = (1.0 - 5.0*rich)**2 - end where - where(rich > rich_trans .and. rich < rich_crit) - mix = ((1.0 - b_stab*rich)/lambda)**2 - end where - -end if +contains -end subroutine monin_obukhov_stable_mix +#include "monin_obukhov_inter_r4.fh" +#include "monin_obukhov_inter_r8.fh" end module monin_obukhov_inter !> @}