!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! !! GNU General Public License !! !! !! !! This file is part of the Flexible Modeling System (FMS). !! !! !! !! FMS is free software; you can redistribute it and/or modify !! !! it and are expected to follow the terms of the GNU General Public !! !! License as published by the Free Software Foundation. !! !! !! !! 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 General Public License !! !! along with FMS; if not, write to: !! !! Free Software Foundation, Inc. !! !! 59 Temple Place, Suite 330 !! !! Boston, MA 02111-1307 USA !! !! or see: !! !! http://www.gnu.org/licenses/gpl.txt !! !! !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! module ocean_density_mod ! ! S.M. Griffies ! ! ! ! Compute density and related quantities. ! ! ! ! ! This module computes the in-situ density and its partial derivatives with ! respect to conservative temperature or potential temperature, and with ! respect to salinity. ! ! Based on Jackett, McDougall, Feistel Wright, and Griffies(2005). ! ! This equation of state is valid over a "cone-shaped" range ! corresponding to ! ! 0psu <= salinity <= 40 psu ! ! -3C <= theta <= 40C "theta" = either conservative or potential temp ! ! 0dbar <= pressure <= 8000dbar ! ! with the cone getting smaller in the deeper ocean where ! theta and salinity vary over a smaller range. ! ! Input variables are the following: ! ! --salinity in psu ! --conservative temperature or potential temperature (theta) in deg C ! --pressure in dbars (1bar = 10dbar = 10^5 Newton/m^2 = 10^5 Pascals). ! ! Note that in the ocean, pressure increases roughly by 1dbar for each meter depth. ! Also note that pressure is the "sea pressure", which is the absolute pressure ! minus the pressure of a standard atmosphere, which is 10.1325 dbars. ! ! check values
! for "theta" = conservative temperature ! rho(s=20psu,theta=20C,p=1000dbar) = 1017.842890411975 (kg/m^3)
! alpha(s=20psu,theta=20C,p=1000dbar) = 2.436057013634649e-4 (1/C)
! beta(s=20psu,theta=20C,p=1000dbar) = 7.314818108935248e-4 (1/psu)
! ! for "theta" = potential temperature ! rho(s=20psu,theta=20C,p=1000dbar) = 1017.728868019642 (kg/m^3)
! alpha(s=20psu,theta=20C,p=1000dbar) = 2.525481286927133e-4 (1/C)
! beta(s=20psu,theta=20C,p=1000dbar) = 7.379638527217575e-4 (1/psu)
! ! This equation of state should be suitable for purposes of realistic ! global ocean climate modeling. ! ! ! B. Linear equation for use in idealized Boussinesq studies ! ! This equation renders density a linear function of potential ! temperature and salinity. All nonlinearities are ignored, as are ! pressure effects. ! ! The valid range for theta and salinity arbitrary for the ! linear equation of state. ! !
! ! ! ! ! Feistel (2003), A new extended Gibbs thermodynamic potential ! of seawater. Progress in Oceanography. vol 58, pages 43-114. ! ! ! ! Jackett, McDougall, Feistel, Wright, and Griffies (2006) ! Algorithms for density, potential temperature, conservative ! temperature, and freezing temperature of seawater. ! Journal of Atmospheric and Oceanic Technology, 2006, ! in press. ! ! ! ! McDougall and Jackett (2005) ! The material derivative of neutral density ! Journal of Marine Research, vol 63, pages 159-185. ! ! ! ! S.M. Griffies, M.J. Harrison, R.C. Pacanowski, and A. Rosati ! A Technical Guide to MOM4 (2003) ! ! ! ! S.M. Griffies, R.C. Pacanowski, R.M. Schmidt, and V. Balaji ! Tracer Conservation with an Explicit Free Surface Method for ! Z-coordinate Ocean Models ! Monthly Weather Review (2001) vol 129 pages 1081--1098 ! ! ! ! T. McDougall (1987) ! Cabbeling, Thermobaricity, and water mass conversion ! JGR vol 92, pages 5448-5464 ! ! ! ! ! Density is computed as a function of conservative temperature (degC) ! or potential temperature (degC), salinity (psu), and in-situ pressure (dbar). ! The pressure contribution includes that from the free surface height ! and the applied atmospheric and/or sea ice pressure. ! ! For vert_coordinate==GEOPOTENTIAL, ZSTAR, or ZSIGMA, baroclinic component of ! hydrostatic pressure is not known until the density is known. In this case, ! the baroclinic pressure contribution to density is lagged by a time step. ! rho(tau) = rho[theta(tau),s(tau), p_atm(tau) + p_fs(tau) + p_baroclinic(tau-1)]. ! This issue does not arise when using vert_coordinate=PRESSURE, PSTAR, or PSIGMA. ! ! ! ! ! ! ! ! ! Set true to write a restart. False setting only for rare ! cases where wish to benchmark model without measuring the cost ! of writing restarts and associated chksums. ! Default is write_a_restart=.true. ! ! ! ! Standard atmospheric pressure (dbar). The realistic ! EOS used in mom4 requires "sea pressure" as an argument ! rather than absolute pressure. Sea pressure is ! absolute pressure minus a standard atmospheric pressure ! of 10.1325dbar. ! ! For models that do have a realistic atmospheric loading, then it ! is appropriate to remove 10.1325dbar prior to computing the EOS. ! For those cases with zero atmospheric pressure, then it is not ! necessary to remove the standard atmosphere. The default for the ! press_standard is 0.0dbar. ! ! ! ! Conservative temperature or potential temperature for ! testing the EOS. ! ! ! Salinity for testing the EOS. ! ! ! Sea pressure for testing the EOS. ! ! ! ! Conservative temperature or potential temperature for ! testing the equation for neutral density. ! ! ! Salinity the equation for neutral density. ! ! ! ! Set to true if wish to use the linear equation of state. ! ! ! Constant "thermal expansion coefficient" for EOS ! rho = rho0 - alpha_linear_eos*theta + beta_linear_eos*salinity ! ! ! Constant "saline contraction coefficient" for EOS ! rho = rho0 - alpha_linear_eos*theta + beta_linear_eos*salinity ! ! ! ! Sea pressure for computing diagnostic potential density of use ! for computing diagnostics with potential density. ! ! ! Minimum potential density used to partition vertical according ! to potential density. ! ! ! Maximum potential density used to partition vertical according ! to potential density. ! ! ! ! Minimum neutral density used to partition vertical according ! to rational polynomial approximation to neutral density. ! ! ! Maximum neutral density used to partition vertical according ! to rational polynomial approximation to neutral density. ! ! ! ! Minimum conservative temperature or potential temperature used to ! partition vertical according to temperature. ! ! ! Maximum conservative temperature or potential temperature used to ! partition vertical according to temperature. ! ! ! ! Number of classes used to partition vertical according to potential density, ! conservative temperature, or potential temperature. Used for diagnostics. ! ! ! ! To smooth the vertical temp and salt derivative for diagnosing ! the buoyancy frequency. Default buoyfreq_smooth_vert=.true. ! ! ! ! To normalize the inverse vertical derivative of neutral density ! for computing the buoyancy frequency. Default epsln_drhodz=1e-10. ! ! ! ! For cases where use the domain masking, it is necessary to initialize the field ! denominator_r to nonzero in order to avoid NaNs in the case when change processor ! layout in between restarts. Note that when use solid wall boundary conditions, ! this logical should remain false in order to bitwise reproduce across restarts. ! Default mask_domain_restart=.false. ! ! ! ! For debugging nonlinear equation of state ! ! ! For debugging, it is often useful to have rho=rho0 uniform. ! ! ! Set true to do bitwise exact global sum. When it is false, the global ! sum will be non-bitwise_exact, but will significantly increase ! efficiency. ! default: do_bitwise_exact_sum=.false. ! ! ! #include use constants_mod, only: epsln, grav, c2dbars use diag_manager_mod, only: register_diag_field, register_static_field, diag_axis_init use diag_manager_mod, only: need_data, send_data use fms_mod, only: write_version_number, mpp_error use fms_mod, only: field_exist, FATAL, WARNING use fms_mod, only: open_namelist_file, check_nml_error, close_file, file_exist use fms_io_mod, only: register_restart_field, save_restart, restore_state use fms_io_mod, only: reset_field_pointer, restart_file_type use mpp_domains_mod, only: mpp_update_domains, mpp_global_sum use mpp_domains_mod, only: BITWISE_EXACT_SUM, NON_BITWISE_EXACT_SUM use mpp_mod, only: stdout, stdlog, mpp_chksum use platform_mod, only: i8_kind use time_manager_mod, only: time_type, increment_time use field_manager_mod, only: fm_get_index use ocean_domains_mod, only: get_local_indices use ocean_parameters_mod, only: GEOPOTENTIAL, ZSTAR, ZSIGMA, PRESSURE, PSTAR, PSIGMA use ocean_parameters_mod, only: CONSERVATIVE_TEMP, POTENTIAL_TEMP use ocean_parameters_mod, only: missing_value, onefourth, onehalf, rho0r, rho0 use ocean_pressure_mod, only: pressure_in_dbars use ocean_types_mod, only: ocean_domain_type, ocean_grid_type, ocean_thickness_type use ocean_types_mod, only: ocean_time_type, ocean_time_steps_type, ocean_options_type use ocean_types_mod, only: ocean_prog_tracer_type, ocean_density_type, ocean_external_mode_type use ocean_types_mod, only: ocean_diag_tracer_type use ocean_util_mod, only: write_timestamp use ocean_workspace_mod, only: wrk1, wrk2, wrk3, wrk4, wrk1_2d, wrk2_2d, wrk3_2d, wrk4_2d implicit none private real, dimension(:), allocatable :: a, b ! polynomial coefficients in the realistic EOS real, dimension(:,:), allocatable :: rhodz_tau ! vertical integral of rho*dzt at time tau real, dimension(:,:), allocatable :: rhodz_taup1 ! vertical integral of rho*dzt at time taup1 real, dimension(:,:,:), allocatable :: denominator_r ! reciprocal of denominator for relastic EOS logical :: linear_eos=.false. ! for use of ideal linear equation of state integer :: vert_coordinate ! for setting which vertical coordinate to use integer :: temperature_variable ! for whether using conservative or potential temp integer :: global_sum_flag ! for determing type of global sum BITWISE/NON ! polynomial coefficients in the realistic EOS real :: a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11 real :: b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12 ! multiplied constants for density partial derivs real :: two_a2, three_a3, two_a6, six_a3, two_a8, two_a10, two_a11, four_a11 real :: two_b2, three_b3, six_b3, four_b4, twelve_b4, three_b7, six_b7 real :: onep5_b8, onep5_b9, two_b9, three_b9, two_b11, three_b11, six_b11, three_b12 ! polynomial coefficients in the neutral density real :: a0n, a1n, a2n, a3n, a4n, a5n, a6n real :: b0n, b1n, b2n, b3n, b4n, b5n, b6n, b7n, b8n, b9n ! some test settings for density real :: s_test=20.0 real :: t_test=20.0 real :: p_test=1000.0 real :: jmfwg_rho real :: jmfwg_alpha real :: jmfwg_beta ! some test settings for neutral density real :: sn_test=35.0 real :: tn_test=20.0 real :: mj_neutralrho ! for linear EOS real :: alpha_linear_eos=0.255 real :: beta_linear_eos =0.0 ! time steps real :: dtts =0.0 ! inverse area (1/m) of k=1 tracer cells real :: area_total_r ! inverse gravity constant real :: grav_r ! for diagnostics manager logical :: used integer :: id_drhodtheta =-1 integer :: id_drhodsalt =-1 integer :: id_drhodpress =-1 integer :: id_sound_speed2 =-1 integer :: id_press =-1 integer :: id_rho =-1 integer :: id_rho0 =-1 integer :: id_neutral_rho =-1 integer :: id_pot_rho =-1 integer :: id_pot_rho_0 =-1 integer :: id_pot_rho_1 =-1 integer :: id_pot_rho_2 =-1 integer :: id_pot_rho_3 =-1 integer :: id_pot_rho_4 =-1 integer :: id_pot_rho_et =-1 integer :: id_pot_rho_nt =-1 integer :: id_pot_rho_wt =-1 integer :: id_rho_average =-1 integer :: id_mass_level =-1 integer :: id_volume_level =-1 integer :: id_drhodz_zt =-1 integer :: id_drhodz_wt =-1 integer :: id_buoyfreq2_zt =-1 integer :: id_buoyfreq2_wt =-1 integer :: id_cabbeling =-1 integer :: id_thermobaricity =-1 integer :: id_int_rhodz =-1 integer :: id_rhoave =-1 integer :: id_pbot_adjust =-1 integer :: id_eta_adjust =-1 integer :: id_eta_adjust_approx =-1 integer :: id_eta_adjust_cstvolume=-1 !for restart integer :: id_restart_rho = 0 type(restart_file_type), save :: Den_restart #include type(ocean_domain_type), pointer :: Dom =>NULL() type(ocean_grid_type), pointer :: Grd =>NULL() character(len=128) :: version=& '$Id: ocean_density.F90,v 16.0.2.6.4.1.2.2.10.5.6.1.4.3 2009/12/04 14:39:46 smg Exp $' character (len=128) :: tagname = & '$Name: mom4p1_pubrel_dec2009_nnz $' public ocean_density_init public ocean_density_end public ocean_density_diag public update_ocean_density public density public potential_density public neutral_density public density_sfc public density_derivs public density_delta_z public density_delta_sfc public ocean_density_restart private ocean_density_chksum private compute_buoyfreq private cabbeling_thermobaricity ! interfaces for density interface density module procedure density_field module procedure density_level module procedure density_line module procedure density_point end interface ! interfaces for neutral density interface neutral_density module procedure neutral_density_field module procedure neutral_density_point end interface ! interfaces for density derivatives interface density_derivs module procedure density_derivs_field module procedure density_derivs_level module procedure density_derivs_point end interface integer :: index_temp=-1 integer :: index_salt=-1 integer :: num_prog_tracers ! indices for diagnostic tracer density elements integer :: ind_rho = -1 integer :: ind_neutralrho = -1 integer :: ind_potrho_0 = -1 integer :: ind_potrho_1 = -1 integer :: ind_potrho_2 = -1 integer :: ind_potrho_3 = -1 integer :: ind_potrho_4 = -1 ! nml settings ! for diagnostic partitioning of vertical according to ! potential density, neutral density, or theta classes integer :: layer_nk = 80 ! # of classes used to compute diagnostics associated with ! potential density, potential temperature, or conservative ! temperature classes. ! for diagnostic partitioning of vertical according to potential density classes real :: potrho_press = 2000.0 ! sea pressure (dbars) for potential density computed for diagnostics real :: potrho_min = 1028.0 ! (kg/m^3) real :: potrho_max = 1038.0 ! (kg/m^3) ! for diagnostic partitioning of vertical according to ! rational polynomial approximation to neutral density real :: neutralrho_min = 1020.0 ! (kg/m^3) real :: neutralrho_max = 1030.0 ! (kg/m^3) ! for diagnostic partitioning of vertical according ! to potential temperature or conservative temperature classes real :: theta_min = -2.0 ! (degrees C) real :: theta_max = 30.0 ! (degrees C) ! standard atmospheric pressure (dbar). ! Should be set to 0.0 if assume zero pressure for the ! overlying atmosphere. But if have a realistic atmospheric ! pressure loading, then set press_standard=10.1325. real :: press_standard = 0.0 ! for smoothing the vertical density gradient ! when diagnosing the buoyancy frequency. logical :: buoyfreq_smooth_vert=.true. integer :: num_121_passes =1 real :: epsln_drhodz =1.e-10 ! for case when use domain masking, logical :: mask_domain_restart = .false. logical :: debug_this_module = .false. logical :: rho0_density = .false. logical :: module_is_initialized = .false. logical :: write_a_restart = .true. logical :: do_bitwise_exact_sum = .false. namelist /ocean_density_nml/ s_test, t_test, p_test, press_standard, & sn_test, tn_test, & linear_eos, alpha_linear_eos, beta_linear_eos, & potrho_press, potrho_min, potrho_max, & neutralrho_min, neutralrho_max, & layer_nk, theta_min, theta_max, & debug_this_module, rho0_density, write_a_restart, & buoyfreq_smooth_vert, num_121_passes, epsln_drhodz, & mask_domain_restart, do_bitwise_exact_sum contains !####################################################################### ! ! ! ! Initialize the density module ! ! subroutine ocean_density_init (Grid, Domain, Time, Time_steps, Thickness, T_prog, T_diag, & Ocean_options, Dens, ver_coordinate, debug) type(ocean_grid_type), target, intent(in) :: Grid type(ocean_domain_type), target, intent(in) :: Domain type(ocean_time_type), intent(in) :: Time type(ocean_time_steps_type), intent(in) :: Time_steps type(ocean_thickness_type), intent(in) :: Thickness type(ocean_prog_tracer_type), intent(in) :: T_prog(:) type(ocean_diag_tracer_type), intent(inout) :: T_diag(:) type(ocean_options_type), intent(inout) :: Ocean_options type(ocean_density_type), intent(inout) :: Dens integer, intent(in) :: ver_coordinate logical, intent(in), optional :: debug integer :: ioun, io_status, ierr integer :: k, n integer :: tau, taup1, taum1 real :: neutralrho_test, rho_test, alpha_test, beta_test, speed2_test real :: drho_dtheta_test, drho_dsal_test, drho_dpress_test real :: diff_test real :: rho0_nk(nk) real, allocatable, dimension(:) :: rho_average real, allocatable, dimension(:) :: mass_level real, allocatable, dimension(:) :: volume_level integer :: id_potrho_bounds, id_potrho_axis integer :: id_potrho_xt, id_potrho_yt integer :: id_neutralrho_bounds, id_neutralrho_axis integer :: id_neutralrho_xt, id_neutralrho_yt integer :: id_theta_bounds, id_theta_axis integer :: id_theta_xt, id_theta_yt integer :: id_restart(5) real, allocatable, dimension(:) :: potrho_bounds real, allocatable, dimension(:) :: neutralrho_bounds real, allocatable, dimension(:) :: theta_bounds real :: potrho_interval real :: neutralrho_interval real :: theta_interval integer :: temp_variable character*128 filename integer :: stdoutunit,stdlogunit stdoutunit=stdout();stdlogunit=stdlog() if ( module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (ocean_density_init): module already initialized.') endif module_is_initialized = .TRUE. tau = Time%tau taup1 = Time%taup1 taum1 = Time%taum1 vert_coordinate = ver_coordinate num_prog_tracers = size(T_prog(:)) do n=1,num_prog_tracers if (T_prog(n)%name == 'temp') index_temp = n if (T_prog(n)%name == 'salt') index_salt = n if (T_prog(n)%longname == 'Conservative temperature') temp_variable = CONSERVATIVE_TEMP if (T_prog(n)%longname == 'Potential temperature') temp_variable = POTENTIAL_TEMP enddo call write_version_number( version, tagname ) ! provide for namelist override of defaults ioun = open_namelist_file() read (ioun,ocean_density_nml,IOSTAT=io_status) write (stdoutunit,'(/)') write (stdoutunit,ocean_density_nml) write (stdlogunit,ocean_density_nml) ierr = check_nml_error(io_status, 'ocean_density_nml') call close_file(ioun) if (PRESENT(debug) .and. .not. debug_this_module) then debug_this_module = debug endif if(debug_this_module) then write(stdoutunit,'(a)') '==>Note: running ocean_density with debug_this_module=.true.' endif if(.not. write_a_restart) then write(stdoutunit,'(a)') '==>Note: running ocean_density with write_a_restart=.false.' write(stdoutunit,'(a)') ' Will NOT write restart file, and so cannot restart the run.' endif if(do_bitwise_exact_sum) then global_sum_flag = BITWISE_EXACT_SUM else global_sum_flag = NON_BITWISE_EXACT_SUM endif if(linear_eos) then write (stdoutunit,'(/1x,a)') & ' ==> Note: USING linear EOS designed for idealized Boussinesq simulations.' write (stdoutunit,'(7x,a)') & 'It is a linear function of potential temperature and salinity.' write (stdoutunit,'(7x,a)') & 'There is no pressure dependence.' Ocean_options%equation_of_state = 'Linear equation of state used for density.' else write (stdoutunit,'(/1x,a)') & ' ==> Note: USING full EOS, as relevant for realistic ocean climate simulations.' write (stdoutunit,'(1x,a,f12.6,a)') & ' Subtracting standard atmosphere of ',press_standard,' dbar for EOS calculation.' Ocean_options%equation_of_state = 'Realistic equation of state used for density.' endif if(temp_variable==CONSERVATIVE_TEMP) then write (stdoutunit,'(/1x,a)') & ' ==> Note: Computing EOS assuming mom4p1 temp = conservative temperature.' elseif(temp_variable==POTENTIAL_TEMP) then write (stdoutunit,'(/1x,a)') & ' ==> Note: Computing EOS assuming mom4p1 temp = potential temperature.' else call mpp_error(FATAL, & '==>Error in ocean_density_mod: model temperature variable remains unspecified') endif write(stdoutunit,*) & '==>Note: The Boussinesq rho0 density has a value of (kg/m^3) ',rho0 if(rho0_density) then write(stdoutunit,*) & '==>Warning: rho0_density=.true, so rho=rho0 everywhere. Is this what you wish to do?' endif ! 25 coefficients in the realistic equation of state if(temp_variable==CONSERVATIVE_TEMP) then jmfwg_rho = 1017.842890411975d0 jmfwg_alpha = 2.436057013634649d-4 jmfwg_beta = 7.314818108935248d-4 a0 = 9.9983912878771446d+02 a1 = 7.0687133522652896d+00 a2 = -2.2746841916232965d-02 a3 = 5.6569114861400121d-04 a4 = 2.3849975952593345d+00 a5 = 3.1761924314867009d-04 a6 = 1.7459053010547962d-03 a7 = 1.2192536310173776d-02 a8 = 2.4643435731663949d-07 a9 = 4.0525405332794888d-06 a10 = -2.3890831309113187d-08 a11 = -5.9016182471196891d-12 b0 = 1.0000000000000000d+00 b1 = 7.0051665739672298d-03 b2 = -1.5040804107377016d-05 b3 = 5.3943915288426715d-07 b4 = 3.3811600427083414d-10 b5 = 1.5599507046153769d-03 b6 = -1.8137352466500517d-06 b7 = -3.3580158763335367d-10 b8 = 5.7149997597561099d-06 b9 = 7.8025873978107375d-10 b10 = 7.1038052872522844d-06 b11 = -2.1692301739460094d-17 b12 = -8.2564080016458560d-18 mj_neutralrho=1024.43863927763d0 a0n = 1.0022048243661291d+003 a1n = 2.0634684367767725d-001 a2n = 8.0483030880783291d-002 a3n = -3.6670094757260206d-004 a4n = -1.4602011474139313d-003 a5n = -2.5860953752447594d-003 a6n = -3.0498135030851449d-007 b0n = 1.0000000000000000d+000 b1n = 4.4946117492521496d-005 b2n = 7.9275128750339643d-005 b3n = -1.2358702241599250d-007 b4n = -4.1775515358142458d-009 b5n = -4.3024523119324234d-004 b6n = 6.3377762448794933d-006 b7n = -7.2640466666916413d-010 b8n = -5.1075068249838284d-005 b9n = -5.8104725917890170d-009 elseif(temp_variable==POTENTIAL_TEMP) then jmfwg_rho = 1017.728868019642d0 jmfwg_alpha = 2.525481286927133d-4 jmfwg_beta = 7.379638527217575d-4 a0 = 9.9984085444849347d+02 a1 = 7.3471625860981584d+00 a2 = -5.3211231792841769d-02 a3 = 3.6492439109814549d-04 a4 = 2.5880571023991390d+00 a5 = -6.7168282786692355d-03 a6 = 1.9203202055760151d-03 a7 = 1.1798263740430364d-02 a8 = 9.8920219266399117d-08 a9 = 4.6996642771754730d-06 a10 = -2.5862187075154352d-08 a11 = -3.2921414007960662d-12 b0 = 1.0000000000000000d+00 b1 = 7.2815210113327091d-03 b2 = -4.4787265461983921d-05 b3 = 3.3851002965802430d-07 b4 = 1.3651202389758572d-10 b5 = 1.7632126669040377d-03 b6 = -8.8066583251206474d-06 b7 = -1.8832689434804897d-10 b8 = 5.7463776745432097d-06 b9 = 1.4716275472242334d-09 b10 = 6.7103246285651894d-06 b11 = -2.4461698007024582d-17 b12 = -9.1534417604289062d-18 mj_neutralrho=1024.59416751197d0 a0n = 1.0023063688892480d+003 a1n = 2.2280832068441331d-001 a2n = 8.1157118782170051d-002 a3n = -4.3159255086706703d-004 a4n = -1.0304537539692924d-004 a5n = -3.1710675488863952d-003 a6n = -1.7052298331414675d-007 b0n = 1.0000000000000000d+000 b1n = 4.3907692647825900d-005 b2n = 7.8717799560577725d-005 b3n = -1.6212552470310961d-007 b4n = -2.3850178558212048d-009 b5n = -5.1268124398160734d-004 b6n = 6.0399864718597388d-006 b7n = -2.2744455733317707d-009 b8n = -3.6138532339703262d-005 b9n = -1.3409379420216683d-009 endif ! save some multiples of the coefficients two_a2 = 2.0*a2 three_a3 = 3.0*a3 six_a3 = 6.0*a3 two_a6 = 2.0*a6 two_a8 = 2.0*a8 two_a10 = 2.0*a10 two_a11 = 2.0*a11 four_a11 = 4.0*a11 two_b2 = 2.0*b2 three_b3 = 3.0*b3 six_b3 = 6.0*b3 four_b4 = 4.0*b4 twelve_b4 = 12.0*b4 three_b7 = 3.0*b7 six_b7 = 6.0*b7 onep5_b8 = 1.5*b8 onep5_b9 = 1.5*b9 two_b9 = 2.0*b9 three_b9 = 3.0*b9 two_b11 = 2.0*b11 three_b11 = 3.0*b11 six_b11 = 6.0*b11 three_b12 = 3.0*b12 #ifndef MOM4_STATIC_ARRAYS call get_local_indices(Domain, isd, ied, jsd, jed, isc, iec, jsc, jec) nk = Grid%nk allocate(Dens%rho(isd:ied,jsd:jed,nk,3)) allocate(Dens%rho_fresh(isd:ied,jsd:jed,nk)) allocate(Dens%potrho(isd:ied,jsd:jed,nk)) allocate(Dens%neutralrho(isd:ied,jsd:jed,nk)) allocate(Dens%pressure_at_depth(isd:ied,jsd:jed,nk)) allocate(Dens%drhodT(isd:ied,jsd:jed,nk)) allocate(Dens%drhodS(isd:ied,jsd:jed,nk)) allocate(Dens%drhodP(isd:ied,jsd:jed,nk)) allocate(Dens%drhodz_wt(isd:ied,jsd:jed,nk)) allocate(Dens%drhodz_zt(isd:ied,jsd:jed,nk)) allocate(Dens%dTdz_zt(isd:ied,jsd:jed,nk)) allocate(Dens%dSdz_zt(isd:ied,jsd:jed,nk)) #endif do k=1,nk Dens%rho_fresh(:,:,k) = 1000.0*Grid%tmask(:,:,k) Dens%potrho(:,:,k) = rho0*Grid%tmask(:,:,k) Dens%neutralrho(:,:,k) = rho0*Grid%tmask(:,:,k) Dens%pressure_at_depth(:,:,k) = rho0*grav*Thickness%depth_zt(:,:,k)*c2dbars enddo Dens%rho(:,:,:,1) = Grid%tmask(:,:,:)*rho0 Dens%rho(:,:,:,2) = Grid%tmask(:,:,:)*rho0 Dens%rho(:,:,:,3) = Grid%tmask(:,:,:)*rho0 Dens%drhodT(:,:,:) = 0.0 Dens%drhodS(:,:,:) = 0.0 Dens%drhodP(:,:,:) = 0.0 Dens%drhodz_wt(:,:,:)= 0.0 Dens%drhodz_zt(:,:,:)= 0.0 Dens%dTdz_zt(:,:,:) = 0.0 Dens%dSdz_zt(:,:,:) = 0.0 Dom => Domain Grd => Grid dtts = Time_steps%dtts ! for diagnostics area_total_r = mpp_global_sum(Dom%domain2d,Grd%dat(:,:)*Grd%tmask(:,:,1), global_sum_flag) if (global_sum_flag .eq. NON_BITWISE_EXACT_SUM) area_total_r = real(area_total_r,kind=FLOAT_KIND) area_total_r = 1.0/(epsln+area_total_r) grav_r = 1.0/grav allocate(rhodz_tau(isd:ied,jsd:jed)) allocate(rhodz_taup1(isd:ied,jsd:jed)) rhodz_tau = 0.0 rhodz_taup1 = 0.0 ! send as 1-dim field, due to problems with diag manager id_rho0 = register_static_field('ocean_model','rho0', Grid%tracer_axes(3:3), & 'reference density for Boussinesq approximation','kg/m^3', & missing_value=missing_value, range=(/-1e0,1e10/), & standard_name='reference_sea_water_density_for_boussinesq_approximation') rho0_nk(:) = rho0 if (id_rho0 > 0) then used = send_data(id_rho0, rho0_nk(:), Time%model_time) endif allocate(denominator_r(isd:ied,jsd:jed,nk)) denominator_r(:,:,:) = 0.0 filename = 'ocean_density.res.nc' id_restart_rho = register_restart_field(Den_restart, filename, 'rho', Dens%rho(:,:,:,taup1), & domain=Dom%domain2d ) id_restart(1) = register_restart_field(Den_restart, filename, 'pressure_at_depth', Dens%pressure_at_depth(:,:,:), & domain=Dom%domain2d ) id_restart(2) = register_restart_field(Den_restart, filename, 'denominator_r', denominator_r(:,:,:), & domain=Dom%domain2d ) id_restart(3) = register_restart_field(Den_restart, filename, 'drhodT', Dens%drhodT(:,:,:), & domain=Dom%domain2d ) id_restart(4) = register_restart_field(Den_restart, filename, 'drhodS', Dens%drhodS(:,:,:), & domain=Dom%domain2d ) id_restart(5) = register_restart_field(Den_restart, filename, 'drhodz_zt', Dens%drhodz_zt(:,:,:), & domain=Dom%domain2d ) filename = 'INPUT/ocean_density.res.nc' if (.NOT.file_exist(trim(filename)) )then Dens%rho(:,:,:,taum1) = density(T_prog(index_salt)%field(:,:,:,tau),& T_prog(index_temp)%field(:,:,:,tau),& Dens%pressure_at_depth(:,:,:)) Dens%rho(:,:,:,tau) = Dens%rho(:,:,:,taum1) Dens%rho(:,:,:,taup1) = Dens%rho(:,:,:,taum1) else write (stdoutunit,'(/a)') ' Reading restart for density from INPUT/ocean_density.res.nc' call restore_state( Den_restart, id_restart_rho ) call mpp_update_domains(Dens%rho(:,:,:,taup1), Dom%domain2d) call restore_state( Den_restart, id_restart(1) ) call mpp_update_domains(Dens%pressure_at_depth(:,:,:),Dom%domain2d) call restore_state( Den_restart, id_restart(2) ) ! initialize to epsln to eliminate NaNs when mask ! out processors and then change layout upon a restart if(mask_domain_restart) then where (denominator_r==0.) denominator_r=rho0r endif call mpp_update_domains(denominator_r(:,:,:),Dom%domain2d) ! determine whether to read density derivs at the initial time step of integration. ! early versions of MOM4p1 did not contain drhodT and drhodS in the restart file, so ! to allow older restart files to be used with newer releases of MOM4p1, we ! provide for the possibility that the restarts do not contain drhodT and drhodS. if(field_exist(filename, 'drhodT')) then call restore_state( Den_restart, id_restart(3) ) call restore_state( Den_restart, id_restart(4) ) call mpp_update_domains(Dens%drhodT(:,:,:),Dom%domain2d) call mpp_update_domains(Dens%drhodS(:,:,:),Dom%domain2d) else write(stdoutunit,'(a)') '==>Note: ocean_density_mod: did not read density derivatives from restart.' endif endif ! compute buoyancy frequency for diagnostic purposes call compute_buoyfreq(Time, Thickness, T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau), Dens) ! over-write drhodz_zt from compute_buoyfreq with drhodz_zt from restart. ! Note that we determine whether to read drhodz_zt at the initial time ! step of integration. early versions of MOM4p1 did not contain drhodz_zt ! in the restart file, so to allow older restart files to be used with ! newer releases of MOM4p1, we provide for the possibility that the ! restarts do not contain drhodz_zt. if (file_exist(trim(filename)) )then if(field_exist(filename, 'drhodz_zt')) then call restore_state( Den_restart, id_restart(5) ) call mpp_update_domains(Dens%drhodz_zt(:,:,:),Dom%domain2d) else write(stdoutunit,'(a)') '==>Note: ocean_density_mod: did not read drhodz_zt from restart.' endif endif ! compute neutral density for diagnostic purposes Dens%neutralrho(:,:,:) = Grd%tmask(:,:,:) & *neutral_density(T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau)) ind_neutralrho = fm_get_index('/ocean_mod/diag_tracers/rho_neutral') if (ind_neutralrho .gt. 0) then T_diag(ind_neutralrho)%field(:,:,:) = Dens%neutralrho(:,:,:) endif ! compute potential density for diagnostic purposes Dens%potrho(:,:,:) = Grd%tmask(:,:,:) & *potential_density(T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau), potrho_press) ! compute potential densities for diagnostic purposes ind_potrho_0 = fm_get_index('/ocean_mod/diag_tracers/rho_pot_0') if (ind_potrho_0 .gt. 0) then T_diag(ind_potrho_0)%field(:,:,:) = Grd%tmask(:,:,:)* & potential_density(T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau), 0.0) endif ind_potrho_1 = fm_get_index('/ocean_mod/diag_tracers/rho_pot_1') if (ind_potrho_1 .gt. 0) then T_diag(ind_potrho_1)%field(:,:,:) = Grd%tmask(:,:,:)* & potential_density(T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau), 1000.0) endif ind_potrho_2 = fm_get_index('/ocean_mod/diag_tracers/rho_pot_2') if (ind_potrho_2 .gt. 0) then T_diag(ind_potrho_2)%field(:,:,:) = Grd%tmask(:,:,:)* & potential_density(T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau), 2000.0) endif ind_potrho_3 = fm_get_index('/ocean_mod/diag_tracers/rho_pot_3') if (ind_potrho_3 .gt. 0) then T_diag(ind_potrho_3)%field(:,:,:) = Grd%tmask(:,:,:)* & potential_density(T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau), 3000.0) endif ind_potrho_4 = fm_get_index('/ocean_mod/diag_tracers/rho_pot_4') if (ind_potrho_4 .gt. 0) then T_diag(ind_potrho_4)%field(:,:,:) = Grd%tmask(:,:,:)* & potential_density(T_prog(index_salt)%field(:,:,:,tau), & T_prog(index_temp)%field(:,:,:,tau), 4000.0) endif if(rho0_density) then Dens%rho(:,:,:,taum1) = Grd%tmask(:,:,:)*rho0 Dens%rho(:,:,:,tau) = Grd%tmask(:,:,:)*rho0 Dens%rho(:,:,:,taup1) = Grd%tmask(:,:,:)*rho0 endif ind_rho = fm_get_index('/ocean_mod/diag_tracers/rho_in_situ') if (ind_rho .gt. 0) then T_diag(ind_rho)%field(:,:,:) = Dens%rho(:,:,:,tau) endif ! compute initial level mass, volume, and density allocate(rho_average(0:nk)) allocate(mass_level(0:nk)) allocate(volume_level(0:nk)) rho_average(:) = 0.0 mass_level(:) = 0.0 volume_level(:) = 0.0 wrk1_2d(:,:) = 0.0 wrk2_2d(:,:) = 0.0 wrk3_2d(:,:) = 0.0 do k=1,nk wrk1_2d(:,:) = Grd%dat(:,:)*Grd%tmask(:,:,k) wrk2_2d(:,:) = wrk1_2d(:,:)*Thickness%dzt(:,:,k) wrk3_2d(:,:) = wrk1_2d(:,:)*Thickness%dzt(:,:,k)*Dens%rho(:,:,k,tau) volume_level(k) = mpp_global_sum(Dom%domain2d,wrk2_2d(:,:),global_sum_flag) mass_level(k) = mpp_global_sum(Dom%domain2d,wrk3_2d(:,:),global_sum_flag) if (global_sum_flag .eq. NON_BITWISE_EXACT_SUM) then volume_level(k) = real(volume_level(k),kind=FLOAT_KIND) mass_level(k) = real(mass_level(k),kind=FLOAT_KIND) endif if(volume_level(k) > 0.0) rho_average(k) = mass_level(k)/volume_level(k) enddo do k=1,nk volume_level(0) = volume_level(0) + volume_level(k) mass_level(0) = mass_level(0) + mass_level(k) enddo if(volume_level(0) > 0.0) rho_average(0) = mass_level(0)/volume_level(0) write(stdoutunit,'(/a,e24.12)') & ' ==>Note: From ocean_density_mod: Boussinesq density rho0(kg/m3) = ',rho0 write(stdoutunit,'(a,e24.12)') & ' Initial rho_average(kg/m3) = ',rho_average(0) if(rho_average(0) /= rho0 .and. Time%init) then write(stdoutunit,'(a)') & ' Since rho0 .ne. rho_average, consider changing rho0 in' write(stdoutunit,'(a/)') & ' ocean_paramters.h to be equal to rho_average for better accuracy.' endif id_rho_average = register_static_field('ocean_model','rho_average', Grid%tracer_axes(3:3), & 'level average density at initial step of segment','kg/m^3', & missing_value=missing_value, range=(/-1e0,1e10/)) id_mass_level = register_static_field('ocean_model','mass_level', Grid%tracer_axes(3:3), & 'mass of levels at initial step of segment','kg', & missing_value=missing_value, range=(/-1e0,1e10/)) id_volume_level= register_static_field('ocean_model','volume_level', Grid%tracer_axes(3:3), & 'volume of levels at initial step of segment','m^3', & missing_value=missing_value, range=(/-1e0,1e10/)) if (id_rho_average > 0) then used = send_data(id_rho_average, rho_average(1:nk), Time%model_time) endif if (id_mass_level > 0) then used = send_data(id_mass_level, mass_level(1:nk), Time%model_time) endif if (id_volume_level > 0) then used = send_data(id_volume_level, volume_level(1:nk), Time%model_time) endif ! Test values for EOS if(.not. linear_eos) then write(stdoutunit,'(/a)') 'From ocean_density_mod: initial density chksums' call write_timestamp(Time%model_time) call ocean_density_chksum(Time, Dens) write (stdoutunit,'(/,a)') 'EQUATION OF STATE TEST VALUES' write (stdoutunit,'(a,f6.2,a,f6.2,a,f8.2)') & 's_test(psu) = ',s_test,', t_test(C) = ',t_test,', p_test(dbar) = ',p_test rho_test = density(s_test,t_test,p_test) write (stdoutunit,' (a,f6.2,a,f6.2,a,f8.2,a,e22.16,a)') & 'rho (',s_test,',',t_test,',',p_test,') = ',rho_test,' kg/m^3' diff_test = rho_test-jmfwg_rho write (stdoutunit,' (a,e22.16,a)') 'diff from JMFWG = ',diff_test,' kg/m^3' call density_derivs(rho_test, s_test, t_test, p_test, & drho_dtheta_test, drho_dsal_test, drho_dpress_test) alpha_test = -drho_dtheta_test/(epsln+rho_test) write (stdoutunit,' (a,f6.2,a,f6.2,a,f8.2,a,e22.16,a)') & 'alpha(',s_test,',',t_test,',',p_test,') = ',alpha_test,' 1/C' diff_test = alpha_test-jmfwg_alpha write (stdoutunit,' (a,e22.16,a)') 'diff from JMFWG = ',diff_test,' 1/C' beta_test = drho_dsal_test /(epsln+rho_test) write (stdoutunit,' (a,f6.2,a,f6.2,a,f8.2,a,e22.16,a)') & 'beta (',s_test,',',t_test,',',p_test,') = ',beta_test,' 1/psu' speed2_test = 1.0/(epsln + drho_dpress_test) write (stdoutunit,' (a,f6.2,a,f6.2,a,f8.2,a,e22.16,a)') & 'squared sound speed (',s_test,',',t_test,',',p_test,') = ',speed2_test,' (m/s)^2' diff_test = beta_test-jmfwg_beta write (stdoutunit,' (a,e22.16,a)') 'diff from JMFWG = ',diff_test,' 1/psu' write (stdoutunit,'(/,a)') 'NEUTRAL DENSITY EQUATION TEST VALUES' write (stdoutunit,'(a,f6.2,a,f6.2)') & 'sn_test(psu) = ',sn_test,', tn_test(C) = ',tn_test neutralrho_test = neutral_density(sn_test,tn_test) write (stdoutunit,' (a,f6.2,a,f6.2,a,e22.16,a)') & 'rho (',sn_test,',',tn_test,') = ',neutralrho_test,' kg/m^3' diff_test = neutralrho_test-mj_neutralrho write (stdoutunit,' (a,e22.16,a)') 'diff from McDougall and Jackett test = ',diff_test,' kg/m^3' endif ! define vertical axes according to potential density classes allocate ( Dens%potrho_ref(layer_nk)) allocate ( potrho_bounds(layer_nk+1)) potrho_bounds(1) = potrho_min potrho_interval = (potrho_max-potrho_min)/(epsln+layer_nk) do k=2,layer_nk+1 potrho_bounds(k)=potrho_bounds(k-1)+potrho_interval enddo do k=1,layer_nk Dens%potrho_ref(k)=potrho_bounds(k)+0.5*potrho_interval enddo ! define vertical axes according to neutral density classes allocate ( Dens%neutralrho_ref(layer_nk)) allocate ( neutralrho_bounds(layer_nk+1)) neutralrho_bounds(1) = neutralrho_min neutralrho_interval = (neutralrho_max-neutralrho_min)/(epsln+layer_nk) do k=2,layer_nk+1 neutralrho_bounds(k)=neutralrho_bounds(k-1)+neutralrho_interval enddo do k=1,layer_nk Dens%neutralrho_ref(k)=neutralrho_bounds(k)+0.5*neutralrho_interval enddo ! define vertical axes according to ! potential temperature or conservative temperature classes allocate ( Dens%theta_ref(layer_nk)) allocate ( theta_bounds(layer_nk+1)) theta_bounds(1) = theta_min theta_interval = (theta_max-theta_min)/(epsln+layer_nk) do k=2,layer_nk+1 theta_bounds(k) =theta_bounds(k-1) +theta_interval enddo do k=1,layer_nk Dens%theta_ref(k) =theta_bounds(k) +0.5*theta_interval enddo ! assuming that if the Grd%name = 'ocean' then we will ! be using this diagnostic axis. Otherwise it is not used. ! This is done to prevent duplicate axis names for multiple ! grid objects. if (trim(Grd%name) == 'ocean') then id_potrho_xt = diag_axis_init ('rho_xt_'//trim(Grd%name),Grd%grid_x_t,'degrees_E','x', & 'tcell longitude',set_name='ocean', Domain2=Dom%domain2d) id_potrho_yt = diag_axis_init ('rho_yt_'//trim(Grd%name),Grd%grid_y_t,'degrees_N','y', & 'tcell latitude',set_name='ocean', Domain2=Dom%domain2d) id_potrho_bounds = diag_axis_init & ( 'potrho_edges',potrho_bounds, 'kg/m^3', 'z','potential density edges',& direction=-1, set_name='ocean') id_potrho_axis = diag_axis_init & ( 'potrho',Dens%potrho_ref,& 'kg/m^3', 'z','potential density',edges=id_potrho_bounds,& direction=-1,set_name='ocean') Dens%potrho_axes = (/ id_potrho_xt, id_potrho_yt, id_potrho_axis /) id_neutralrho_xt = diag_axis_init ('neutralrho_xt_'//trim(Grd%name),Grd%grid_x_t,'degrees_E','x', & 'tcell longitude',set_name='ocean', Domain2=Dom%domain2d) id_neutralrho_yt = diag_axis_init ('neutralrho_yt_'//trim(Grd%name),Grd%grid_y_t,'degrees_N','y', & 'tcell latitude',set_name='ocean', Domain2=Dom%domain2d) id_neutralrho_bounds = diag_axis_init & ( 'neutralrho_edges',neutralrho_bounds, 'kg/m^3', 'z','neutral density edges',& direction=-1, set_name='ocean') id_neutralrho_axis = diag_axis_init & ( 'neutral',Dens%neutralrho_ref,& 'kg/m^3', 'z','neutral density',edges=id_neutralrho_bounds,& direction=-1,set_name='ocean') Dens%neutralrho_axes = (/ id_neutralrho_xt, id_neutralrho_yt, id_neutralrho_axis /) id_theta_xt = diag_axis_init ('theta_xt_'//trim(Grd%name),Grd%grid_x_t,'degrees_E','x', & 'tcell longitude',set_name='ocean', Domain2=Dom%domain2d) id_theta_yt = diag_axis_init ('theta_yt_'//trim(Grd%name),Grd%grid_y_t,'degrees_N','y', & 'tcell latitude', set_name='ocean', Domain2=Dom%domain2d) id_theta_bounds = diag_axis_init & ( 'theta_edges',potrho_bounds, 'C', 'z','potential or conservative temperature edges',& direction=1, set_name='ocean') id_theta_axis = diag_axis_init & ( 'theta',Dens%theta_ref, 'C', 'z','potential or conservative temperature',edges=id_theta_bounds, & direction=1,set_name='ocean') Dens%theta_axes = (/ id_theta_xt, id_theta_yt, id_theta_axis /) endif ! register diagnostic fields for diag_manager id_press = register_diag_field ('ocean_model', 'press', Grd%tracer_axes(1:3),& Time%model_time, 'absolute pressure', 'dbar', & missing_value=missing_value, range=(/-10.,6000./)) id_rho = register_diag_field ('ocean_model', 'rho', Grd%tracer_axes(1:3), & Time%model_time, 'in situ density', 'kg/m^3', & missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho = register_diag_field ('ocean_model', 'pot_rho', Grd%tracer_axes(1:3), & Time%model_time, 'potential density', 'kg/m^3', & missing_value=missing_value, range=(/-10.0,1e5/)) id_neutral_rho = register_diag_field ('ocean_model', 'neutral_rho', Grd%tracer_axes(1:3), & Time%model_time, 'polynomial estimate of neutral density', 'kg/m^3', & missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho_0 = register_diag_field ('ocean_model', 'pot_rho_0', Grd%tracer_axes(1:3), & Time%model_time, 'potential density referenced to 0 dbar', 'kg/m^3', & missing_value=missing_value, range=(/-10.0,1e5/), & standard_name='sea_water_potential_density') id_pot_rho_1 = register_diag_field ('ocean_model', 'pot_rho_1', Grd%tracer_axes(1:3), & Time%model_time, 'potential density referenced to 1000 dbar', 'kg/m^3',& missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho_2 = register_diag_field ('ocean_model', 'pot_rho_2', Grd%tracer_axes(1:3), & Time%model_time, 'potential density referenced to 2000 dbar', 'kg/m^3',& missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho_3 = register_diag_field ('ocean_model', 'pot_rho_3', Grd%tracer_axes(1:3), & Time%model_time, 'potential density referenced to 3000 dbar', 'kg/m^3',& missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho_4 = register_diag_field ('ocean_model', 'pot_rho_4', Grd%tracer_axes(1:3), & Time%model_time, 'potential density referenced to 4000 dbar', 'kg/m^3',& missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho_et = register_diag_field ('ocean_model', 'pot_rho_et', Grd%tracer_axes_flux_x(1:3), & Time%model_time, 'potential density at east face of tracer cell', 'kg/m^3', & missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho_nt = register_diag_field ('ocean_model', 'pot_rho_nt', Grd%tracer_axes_flux_y(1:3), & Time%model_time, 'potential density at north face of tracer cell', 'kg/m^3', & missing_value=missing_value, range=(/-10.0,1e5/)) id_pot_rho_wt = register_diag_field ('ocean_model', 'pot_rho_wt', Grd%tracer_axes_wt(1:3), & Time%model_time, 'potential density at wt points', 'kg/m^3', & missing_value=missing_value, range=(/-10.0,1e5/)) id_drhodtheta = register_diag_field ('ocean_model', 'drhodtheta', Grd%tracer_axes(1:3), & Time%model_time, 'd(rho)/d(theta)', 'kg/m^3/C', & missing_value=-1e10, range=(/-1e10,1e10/)) id_drhodsalt = register_diag_field ('ocean_model', 'drhodsalinity', Grd%tracer_axes(1:3), & Time%model_time, 'd(rho)/d(salinity)', 'kg/m^3/psu', & missing_value=missing_value, range=(/-1e9,1e9/)) id_drhodpress = register_diag_field ('ocean_model', 'drhodpress', Grd%tracer_axes(1:3), & Time%model_time, 'd(rho)/d(press)', 'kg/m^3/Pa', & missing_value=missing_value, range=(/-1e9,1e9/)) id_sound_speed2 = register_diag_field ('ocean_model', 'sound_speed2', Grd%tracer_axes(1:3),& Time%model_time, 'squared sound speed = 1/[d(rho)/d(press)]', '(m/s)^2', & missing_value=missing_value, range=(/-1e9,1e9/)) id_cabbeling = register_diag_field ('ocean_model', 'cabbeling', Grd%tracer_axes(1:3), & Time%model_time, 'cabbeling parameter', '(1/degC)^2', & missing_value=-1e10, range=(/-1e10,1e10/)) id_thermobaricity = register_diag_field ('ocean_model', 'thermobaricity', Grd%tracer_axes(1:3), & Time%model_time, 'thermobaricity parameter', '1/(dbar*degC)', & missing_value=-1e10, range=(/-1e10,1e10/)) id_buoyfreq2_zt = register_diag_field ('ocean_model','buoyfreq2_zt', & Grd%tracer_axes(1:3), Time%model_time, & 'Squared buoyancy frequency at T-point', '1/s^2', & missing_value=missing_value, range=(/-1e6,1e6/)) id_buoyfreq2_wt = register_diag_field ('ocean_model','buoyfreq2_wt', & Grd%tracer_axes_wt(1:3), Time%model_time, & 'Squared buoyancy frequency at T-cell bottom', '1/s^2', & missing_value=missing_value, range=(/-1e6,1e6/)) id_drhodz_zt = register_diag_field ('ocean_model','drhodz_zt', & Grd%tracer_axes(1:3), Time%model_time, & 'd(neutral rho)/dz at T-point', 'kg/m^4', & missing_value=missing_value, range=(/-1e6,1e6/)) id_drhodz_wt = register_diag_field ('ocean_model','drhodz_wt', & Grd%tracer_axes_wt(1:3), Time%model_time, & 'd(neutral rho)/dz at W-point', 'kg/m^4', & missing_value=missing_value, range=(/-1e6,1e6/)) id_int_rhodz = register_diag_field ('ocean_model','int_rhodz', & Grd%tracer_axes(1:2), Time%model_time, & 'vertical sum of in-situ density times cell thickness dz', 'kg/m^2',& missing_value=missing_value, range=(/-1e1,1e20/)) id_rhoave = register_diag_field('ocean_model','rhoave', & Time%model_time, 'global mean ocean in-situ density from ocean_density_mod',& 'kg/m^3', missing_value=missing_value, range=(/-1e10,1e10/)) id_pbot_adjust = register_diag_field('ocean_model','pbot_adjust', & Time%model_time, 'pbot adjustment to counteract spurious mass source in Boussinesq fluid',& 'dbar', missing_value=missing_value, range=(/-1e10,1e10/)) id_eta_adjust = register_diag_field('ocean_model','eta_adjust', & Time%model_time, 'global eta adjustment to include steric effect in Boussinesq fluid',& 'm', missing_value=missing_value, range=(/-100.0,100.0/)) id_eta_adjust_approx = register_diag_field('ocean_model','eta_adjust_approx', & Time%model_time, 'approximate global eta adjustment to include steric effect in Boussinesq fluid',& 'm', missing_value=missing_value, range=(/-100.0,100.0/)) id_eta_adjust_cstvolume = register_diag_field('ocean_model','eta_adjust_cstvolume', & Time%model_time, 'global eta adjustment (assuming constant volume) to include steric effect in Boussinesq fluid',& 'm', missing_value=missing_value, range=(/-100.0,100.0/)) end subroutine ocean_density_init ! NAME="ocean_density_init" !####################################################################### ! ! ! ! Diagnose pressure_at_depth and diagnostic ocean density fields. ! Also send some diagnostics to diagnostic manager. ! ! subroutine ocean_density_diag(Time, Temp, Salt, Dens, T_diag) type(ocean_time_type), intent(in) :: Time type(ocean_prog_tracer_type), intent(in) :: Temp type(ocean_prog_tracer_type), intent(in) :: Salt type(ocean_density_type), intent(inout) :: Dens type(ocean_diag_tracer_type), intent(inout) :: T_diag(:) logical :: used integer :: tau tau = Time%tau if (ind_rho .gt. 0) then T_diag(ind_rho)%field(:,:,:) = Dens%rho(:,:,:,tau) endif ! compute neutral density for diagnostic purposes Dens%neutralrho(:,:,:) = Grd%tmask(:,:,:) & *neutral_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau)) if (ind_neutralrho .gt. 0) then T_diag(ind_neutralrho)%field(:,:,:) = Dens%neutralrho(:,:,:) endif ! compute potential density for diagnostic purposes Dens%potrho(:,:,:) = Grd%tmask(:,:,:) & *potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), potrho_press) ! compute potential densities for diagnostic purposes if (ind_potrho_0 .gt. 0) then T_diag(ind_potrho_0)%field(:,:,:) = Grd%tmask(:,:,:) * & potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 0.0) endif if (ind_potrho_1 .gt. 0) then T_diag(ind_potrho_1)%field(:,:,:) = Grd%tmask(:,:,:) * & potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 1000.0) endif if (ind_potrho_2 .gt. 0) then T_diag(ind_potrho_2)%field(:,:,:) = Grd%tmask(:,:,:) * & potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 2000.0) endif if (ind_potrho_3 .gt. 0) then T_diag(ind_potrho_3)%field(:,:,:) = Grd%tmask(:,:,:) * & potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 3000.0) endif if (ind_potrho_4 .gt. 0) then T_diag(ind_potrho_4)%field(:,:,:) = Grd%tmask(:,:,:) * & potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 4000.0) endif if (id_neutral_rho > 0) & used = send_data (id_neutral_rho, Dens%neutralrho(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) if (id_pot_rho > 0) & used = send_data (id_pot_rho, Dens%potrho(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) if (id_pot_rho_0 > 0) then if (ind_potrho_0 .gt. 0) then used = send_data (id_pot_rho_0, T_diag(ind_potrho_0)%field(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) else wrk1(:,:,:) = potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 0.0) used = send_data (id_pot_rho_0, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif endif if (id_pot_rho_1 > 0) then if (ind_potrho_1 .gt. 0) then used = send_data (id_pot_rho_1, T_diag(ind_potrho_1)%field(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) else wrk1(:,:,:) = potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 1000.0) used = send_data (id_pot_rho_1, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif endif if (id_pot_rho_2 > 0) then if (ind_potrho_2 .gt. 0) then used = send_data (id_pot_rho_2, T_diag(ind_potrho_2)%field(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) else wrk1(:,:,:) = potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 2000.0) used = send_data (id_pot_rho_2, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:),& is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif endif if (id_pot_rho_3 > 0) then if (ind_potrho_3 .gt. 0) then used = send_data (id_pot_rho_3, T_diag(ind_potrho_3)%field(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) else wrk1(:,:,:) = potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 3000.0) used = send_data (id_pot_rho_3, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif endif if (id_pot_rho_4 > 0) then if (ind_potrho_4 .gt. 0) then used = send_data (id_pot_rho_4, T_diag(ind_potrho_4)%field(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) else wrk1(:,:,:) = potential_density(Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), 4000.0) used = send_data (id_pot_rho_4, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif endif end subroutine ocean_density_diag ! NAME="ocean_density_diag" !####################################################################### ! ! ! ! Diagnose pressure_at_depth and ocean density. ! Also send some diagnostics to diagnostic manager. ! ! subroutine update_ocean_density(Time, Thickness, Temp, Salt, Ext_mode, Dens) type(ocean_time_type), intent(in) :: Time type(ocean_thickness_type), intent(in) :: Thickness type(ocean_prog_tracer_type), intent(in) :: Temp type(ocean_prog_tracer_type), intent(in) :: Salt type(ocean_external_mode_type), intent(in) :: Ext_mode type(ocean_density_type), intent(inout) :: Dens type(time_type) :: next_time logical :: used integer :: i, j, k integer :: tau, taup1 real :: mass, massip1, massjp1 real :: density_tau =0.0 real :: density_taup1 =0.0 real :: volume_tau =0.0 real :: volume_taup1 =0.0 real :: volume_taup12 =0.0 real :: mass_tau =0.0 real :: mass_taup1 =0.0 real :: dArea =0.0 real :: pbot_adjust =0.0 real :: rhoave =0.0 real :: eta_adjust =0.0 real :: eta_adjust_approx =0.0 real :: eta_adjust_cstvolume=0.0 integer :: stdoutunit stdoutunit=stdout() tau = Time%tau taup1 = Time%taup1 ! compute pressure at depth (dbars) if(vert_coordinate==GEOPOTENTIAL) then Dens%pressure_at_depth(:,:,:) = pressure_in_dbars(Thickness, Dens%rho(:,:,:,tau), & Ext_mode%patm_t(:,:,tau)+grav*Dens%rho(:,:,1,tau)*Ext_mode%eta_t(:,:,tau)) elseif(vert_coordinate==ZSTAR .or. vert_coordinate==ZSIGMA) then Dens%pressure_at_depth(:,:,:) = pressure_in_dbars(Thickness, Dens%rho(:,:,:,tau), & Ext_mode%patm_t(:,:,tau)) elseif(vert_coordinate==PRESSURE) then do k=1,nk do j=jsd,jed do i=isd,ied Dens%pressure_at_depth(i,j,k) = c2dbars*Thickness%depth_st(i,j,k) enddo enddo enddo elseif(vert_coordinate==PSTAR) then do k=1,nk do j=jsd,jed do i=isd,ied Dens%pressure_at_depth(i,j,k) = c2dbars*( & Ext_mode%patm_t(i,j,tau) & + Thickness%depth_st(i,j,k)*Thickness%pbot0r(i,j) & *(Ext_mode%pbot_t(i,j,tau)-Ext_mode%patm_t(i,j,tau)) & ) enddo enddo enddo elseif(vert_coordinate==PSIGMA) then do k=1,nk do j=jsd,jed do i=isd,ied Dens%pressure_at_depth(i,j,k) = c2dbars*( & Ext_mode%patm_t(i,j,tau) & + Thickness%depth_st(i,j,k) & *(Ext_mode%pbot_t(i,j,tau)-Ext_mode%patm_t(i,j,tau)) & ) enddo enddo enddo endif ! diagnose in situ density Dens%rho(:,:,:,taup1) = Grd%tmask(:,:,:) & *density(Salt%field(:,:,:,taup1), Temp%field(:,:,:,taup1), Dens%pressure_at_depth(:,:,:)) if(rho0_density) then Dens%rho(:,:,:,taup1) = Grd%tmask(:,:,:)*rho0 endif ! compute drhodT and drhodS and drhodP call density_derivs(Dens%rho(:,:,:,tau), Salt%field(:,:,:,tau), & Temp%field(:,:,:,tau), Dens%pressure_at_depth(:,:,:), & Time, Dens%drhodT(:,:,:), Dens%drhodS(:,:,:), Dens%drhodP(:,:,:)) ! compute cabbeling and thermobaricity parameters for diagnostics if(id_cabbeling > 0 .or. id_thermobaricity > 0) then call cabbeling_thermobaricity(Dens%rho(:,:,:,tau), Salt%field(:,:,:,tau), & Temp%field(:,:,:,tau), Dens%pressure_at_depth(:,:,:), & Time, Dens%drhodT(:,:,:), Dens%drhodS(:,:,:), Dens%drhodP(:,:,:)) endif ! compute buoyancy frequency for diagnostic purposes call compute_buoyfreq(Time, Thickness, Salt%field(:,:,:,tau), Temp%field(:,:,:,tau), Dens) if (id_press > 0) & used = send_data (id_press, Dens%pressure_at_depth(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) if (id_rho > 0) & used = send_data (id_rho, Dens%rho(:,:,:,tau), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) if(id_int_rhodz > 0) then wrk1_2d(:,:) = 0.0 do k=1,nk do j=jsc,jec do i=isc,iec wrk1_2d(i,j) = wrk1_2d(i,j) + Thickness%dzt(i,j,k)*Dens%rho(i,j,k,tau) enddo enddo enddo used = send_data (id_int_rhodz, wrk1_2d(:,:), & Time%model_time,rmask=Grd%tmask(:,:,1), & is_in=isc, js_in=jsc, ie_in=iec, je_in=jec) endif next_time = increment_time(Time%model_time, int(dtts), 0) if (need_data(id_pot_rho_wt,next_time)) then wrk1(:,:,:) = 0.0 do j=jsc,jec do i=isc,iec wrk1(i,j,nk) = Dens%potrho(i,j,nk) enddo enddo do k=1,nk-1 do j=jsc,jec do i=isc,iec if(Grd%tmask(i,j,k) > 0.0) then wrk1(i,j,k) = ( Grd%tmask(i,j,k+1)*Dens%potrho(i,j,k+1)*Thickness%rho_dzt(i,j,k+1,tau) & +Dens%potrho(i,j,k) *Thickness%rho_dzt(i,j,k,tau)) & /( epsln + Thickness%rho_dzt(i,j,k,tau) + Grd%tmask(i,j,k+1)*Thickness%rho_dzt(i,j,k+1,tau) ) endif enddo enddo enddo used = send_data (id_pot_rho_wt, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif if (need_data(id_pot_rho_et,next_time)) then wrk1(:,:,:) = 0.0 do k=1,nk do j=jsc,jec do i=isc,iec mass = Thickness%rho_dzt(i,j,k,tau) *Grd%dat(i,j) *Grd%tmask(i,j,k) massip1 = Thickness%rho_dzt(i+1,j,k,tau)*Grd%dat(i+1,j)*Grd%tmask(i+1,j,k) wrk1(i,j,k) = ( Dens%potrho(i,j,k)*mass + Dens%potrho(i+1,j,k)*massip1 ) & /( epsln + mass + massip1 ) enddo enddo enddo used = send_data (id_pot_rho_et, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif if (need_data(id_pot_rho_nt,next_time)) then wrk1(:,:,:) = 0.0 do k=1,nk do j=jsc,jec do i=isc,iec mass = Thickness%rho_dzt(i,j,k,tau) *Grd%dat(i,j) *Grd%tmask(i,j,k) massjp1 = Thickness%rho_dzt(i,j+1,k,tau)*Grd%dat(i,j+1)*Grd%tmask(i,j+1,k) wrk1(i,j,k) = ( Dens%potrho(i,j,k)*mass + Dens%potrho(i,j+1,k)*massjp1 ) & /( epsln + mass + massjp1 ) enddo enddo enddo used = send_data (id_pot_rho_nt, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif if (id_pbot_adjust>0 .or. id_eta_adjust>0 .or. & id_eta_adjust_approx>0 .or. id_eta_adjust_cstvolume>0 .or. id_rhoave>0) then ! These diagnostics are used to adjust the bottom pressure and surface height computed ! from a Boussinesq model. The adjustments correct, globally, for the spurious ! mass sources appearing in the Boussinesq fluid and the missing steric effect. ! The adjustments are NOT needed with non-Boussinesq models (pressure based vert coord), ! since the non-Boussinesq fluid correctly computes the bottom pressure and ! surface height according to mass conserving kinematics. ! ! In a Bouss model (depth based vert coordinates), when global mean density increases, ! so does the Boussinesq mass. So the pbot_adjust is negative in this case, in ! order to globally counteract effects from the spurious mass source. ! ! In a non-Bouss model, when global mean density increases, global mean sea level decreases. ! This global steric effect is absent from the Boussinesq fluid. To incorporate this ! this missing contribution to sea level, eta_adjust will be negative in this case. ! ! note that dzt has already been updated to its taup1 value. that is why we use ! rho0r*rho_dzt = dzt (when depth-based vertical coordinates). mass_tau = 0.0 mass_taup1 = 0.0 volume_tau = 0.0 volume_taup1 = 0.0 volume_taup12 = 0.0 rhodz_tau(:,:) = 0.0 rhodz_taup1(:,:) = 0.0 wrk1_2d(:,:) = 0.0 wrk2_2d(:,:) = 0.0 wrk3_2d(:,:) = 0.0 wrk4_2d(:,:) = 0.0 ! do the vertical sum of rho*dzt if(vert_coordinate==GEOPOTENTIAL .or. vert_coordinate==ZSTAR .or. vert_coordinate==ZSIGMA) then do k=1,nk do j=jsc,jec do i=isc,iec rhodz_tau(i,j) = rhodz_tau(i,j) + Grd%tmask(i,j,k)*rho0r*Thickness%rho_dzt(i,j,k,tau) & *Dens%rho(i,j,k,tau) rhodz_taup1(i,j)= rhodz_taup1(i,j)+ Grd%tmask(i,j,k)*rho0r*Thickness%rho_dzt(i,j,k,taup1) & *Dens%rho(i,j,k,taup1) enddo enddo enddo else k=1 do j=jsc,jec do i=isc,iec rhodz_tau(i,j) = Grd%tmask(i,j,k)*grav_r*(Ext_mode%pbot_t(i,j,tau) -Ext_mode%patm_t(i,j,tau)) rhodz_taup1(i,j) = Grd%tmask(i,j,k)*grav_r*(Ext_mode%pbot_t(i,j,taup1)-Ext_mode%patm_t(i,j,taup1)) enddo enddo endif ! compute the mass and volume of a seawater column do j=jsd,jed do i=isd,ied wrk1_2d(i,j) = Grd%tmask(i,j,1)*Grd%dat(i,j)*rhodz_tau(i,j) wrk2_2d(i,j) = Grd%tmask(i,j,1)*Grd%dat(i,j)*rhodz_taup1(i,j) wrk3_2d(i,j) = Grd%tmask(i,j,1)*Grd%dat(i,j)*(Grd%ht(i,j) + Ext_mode%eta_t(i,j,tau)) wrk4_2d(i,j) = Grd%tmask(i,j,1)*Grd%dat(i,j)*(Grd%ht(i,j) + Ext_mode%eta_t(i,j,taup1)) enddo enddo ! perform global sums to get global mass and volume for ocean mass_tau = mpp_global_sum(Dom%domain2d,wrk1_2d(:,:),NON_BITWISE_EXACT_SUM) volume_tau = mpp_global_sum(Dom%domain2d,wrk3_2d(:,:),NON_BITWISE_EXACT_SUM) density_tau = mass_tau/(epsln+volume_tau) mass_taup1 = mpp_global_sum(Dom%domain2d,wrk2_2d(:,:),NON_BITWISE_EXACT_SUM) volume_taup1 = mpp_global_sum(Dom%domain2d,wrk4_2d(:,:),NON_BITWISE_EXACT_SUM) density_taup1 = mass_taup1/(epsln+volume_taup1) volume_taup12 = 0.5*(volume_taup1+volume_tau) if(id_pbot_adjust > 0) then pbot_adjust = -grav*c2dbars*area_total_r*volume_taup1*(density_taup1-density_tau) used = send_data(id_pbot_adjust, pbot_adjust, Time%model_time) endif if(id_eta_adjust > 0) then eta_adjust = area_total_r*volume_taup12*log((density_tau+epsln)/(density_taup1+epsln)) used = send_data(id_eta_adjust, eta_adjust, Time%model_time) endif if(id_eta_adjust_approx > 0) then eta_adjust_approx = area_total_r*volume_taup1*(density_tau/(epsln+density_taup1)-1.0) used = send_data(id_eta_adjust_approx, eta_adjust_approx, Time%model_time) endif if(id_eta_adjust_cstvolume > 0) then eta_adjust_cstvolume = area_total_r*Grd%tcellv*(density_tau/(epsln+density_taup1)-1.0) used = send_data(id_eta_adjust_cstvolume, eta_adjust_cstvolume, Time%model_time) endif if(id_rhoave > 0) then used = send_data(id_rhoave, density_tau, Time%model_time) endif endif if(debug_this_module) then write(stdoutunit,'(a)') ' ' write(stdoutunit,*) 'From ocean_density_mod: density chksums' call write_timestamp(Time%model_time) call ocean_density_chksum(Time, Dens) endif end subroutine update_ocean_density ! NAME="update_ocean_density" !####################################################################### ! ! ! ! Compute density for all grid points. ! ! Note that pressure here is ! ! sea pressure = absolute pressure - press_standard (dbars) ! ! and salinity is in model units (psu). ! ! ! function density_field (salinity, theta, press) real, dimension(isd:,jsd:,:), intent(in) :: salinity real, dimension(isd:,jsd:,:), intent(in) :: theta real, dimension(isd:,jsd:,:), intent(in) :: press real, dimension(isd:ied,jsd:jed,nk) :: density_field integer :: i, j, k real :: t1, t2, s1, sp5, p1, p1t1 real :: num, den if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_field): module must be initialized') endif if(linear_eos) then do k=1,nk do j=jsd,jed do i=isd,ied density_field(i,j,k) = rho0 - alpha_linear_eos*theta(i,j,k) + beta_linear_eos*salinity(i,j,k) enddo enddo enddo else do k=1,nk do j=jsd,jed do i=isd,ied t1 = theta(i,j,k) t2 = t1*t1 s1 = salinity(i,j,k) sp5 = sqrt(s1) p1 = press(i,j,k) - press_standard p1t1 = p1*t1 num = a0 + t1*(a1 + t1*(a2+a3*t1) ) & + s1*(a4 + a5*t1 + a6*s1) & + p1*(a7 + a8*t2 + a9*s1 + p1*(a10+a11*t2)) den = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) & + p1*(b10 + p1t1*(b11*t2 + b12*p1)) denominator_r(i,j,k) = 1.0/(epsln+den) density_field(i,j,k) = num*denominator_r(i,j,k) enddo enddo enddo endif end function density_field ! NAME="density_field" !####################################################################### ! ! ! ! Compute density at a particular k-level. ! ! Note that pressure here is ! ! sea pressure = absolute pressure - press_standard (dbars) ! ! ! function density_level(salinity, theta, press) real, dimension(isd:,jsd:), intent(in) :: salinity real, dimension(isd:,jsd:), intent(in) :: theta real, dimension(isd:,jsd:), intent(in) :: press real, dimension(isd:ied,jsd:jed) :: density_level integer :: i, j real :: t1, t2, s1, sp5, p1, p1t1 real :: num, den if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_level): module must be initialized') endif if(linear_eos) then do j=jsd,jed do i=isd,ied density_level(i,j) = rho0 - alpha_linear_eos*theta(i,j) + beta_linear_eos*salinity(i,j) enddo enddo else do j=jsd,jed do i=isd,ied t1 = theta(i,j) t2 = t1*t1 s1 = salinity(i,j) sp5 = sqrt(s1) p1 = press(i,j) - press_standard p1t1 = p1*t1 num = a0 + t1*(a1 + t1*(a2+a3*t1) ) & + s1*(a4 + a5*t1 + a6*s1) & + p1*(a7 + a8*t2 + a9*s1 + p1*(a10+a11*t2)) den = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) & + p1*(b10 + p1t1*(b11*t2 + b12*p1)) density_level(i,j) = num/(epsln+den) enddo enddo endif end function density_level ! NAME="density_level" !####################################################################### ! ! ! ! Compute density at a particular k-level and j index. This scheme ! is used in the vectorized version of the full convection scheme. ! ! Note that pressure here is ! ! sea pressure = absolute pressure - press_standard ! ! ! function density_line(salinity, theta, press) real, dimension(isd:), intent(in) :: salinity real, dimension(isd:), intent(in) :: theta real, dimension(isd:), intent(in) :: press real, dimension(isd:ied) :: density_line integer :: i real :: t1, t2, s1, sp5, p1, p1t1 real :: num, den if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_line): module must be initialized') endif if(linear_eos) then do i=isd,ied density_line(i) = rho0 - alpha_linear_eos*theta(i) + beta_linear_eos*salinity(i) enddo else do i=isd,ied t1 = theta(i) t2 = t1*t1 s1 = salinity(i) sp5 = sqrt(s1) p1 = press(i) - press_standard p1t1 = p1*t1 num = a0 + t1*(a1 + t1*(a2+a3*t1) ) & + s1*(a4 + a5*t1 + a6*s1) & + p1*(a7 + a8*t2 + a9*s1 + p1*(a10+a11*t2)) den = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) & + p1*(b10 + p1t1*(b11*t2 + b12*p1)) density_line(i) = num/(epsln+den) enddo endif end function density_line ! NAME="density_line" !####################################################################### ! ! ! ! Compute neutral density according to a rational polynomial ! approximation given by McDougall and Jackett (2005). ! ! function neutral_density_field (salinity, theta) real, dimension(isd:,jsd:,:), intent(in) :: salinity real, dimension(isd:,jsd:,:), intent(in) :: theta real, dimension(isd:ied,jsd:jed,nk) :: neutral_density_field integer :: i, j, k real :: t1, t2, s1, sp5 real :: num, den if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (neutral_density_field): module must be initialized') endif if(linear_eos) then do k=1,nk do j=jsd,jed do i=isd,ied neutral_density_field(i,j,k) = rho0 - alpha_linear_eos*theta(i,j,k) + beta_linear_eos*salinity(i,j,k) enddo enddo enddo else do k=1,nk do j=jsd,jed do i=isd,ied t1 = theta(i,j,k) t2 = t1*t1 s1 = salinity(i,j,k) sp5 = sqrt(s1) num = a0n + t1*(a1n + t1*(a2n+a3n*t1) ) & + s1*(a4n + a5n*t1 + a6n*s1) den = b0n + t1*(b1n + t1*(b2n + t1*(b3n + t1*b4n))) & + s1*(b5n + t1*(b6n + b7n*t2) + sp5*(b8n + b9n*t2)) neutral_density_field(i,j,k) = num/(epsln+den) enddo enddo enddo endif ! endif for linear_eos end function neutral_density_field ! NAME="neutral_density_field" !####################################################################### ! ! ! ! Compute neutral density according to a rational polynomial ! approximation given by McDougall and Jackett (2005). ! ! function neutral_density_point (salinity, theta) real, intent(in) :: salinity real, intent(in) :: theta real :: neutral_density_point real :: t1, t2, s1, sp5 real :: num, den if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (neutral_density_point): module must be initialized') endif if(linear_eos) then neutral_density_point = rho0 - alpha_linear_eos*theta + beta_linear_eos*salinity else t1 = theta t2 = t1*t1 s1 = salinity sp5 = sqrt(s1) num = a0n + t1*(a1n + t1*(a2n+a3n*t1) ) & + s1*(a4n + a5n*t1 + a6n*s1) den = b0n + t1*(b1n + t1*(b2n + t1*(b3n + t1*b4n))) & + s1*(b5n + t1*(b6n + b7n*t2) + sp5*(b8n + b9n*t2)) neutral_density_point = num/(epsln+den) endif ! endif for linear_eos end function neutral_density_point ! NAME="neutral_density_point" !####################################################################### ! ! ! ! Compute potential density referenced to some given sea pressure. ! ! Note that potential density referenced to the surface (i.e., sigma_0) ! has a zero sea pressure, so pressure=0.0 should be the argument ! to the function. ! ! Note that pressure here is ! sea pressure = absolute pressure - press_standard (dbars) ! ! ! function potential_density (salinity, theta, pressure) real, dimension(isd:,jsd:,:), intent(in) :: salinity real, dimension(isd:,jsd:,:), intent(in) :: theta real, intent(in) :: pressure real, dimension(isd:ied,jsd:jed,nk) :: potential_density integer :: i, j, k real :: t1, t2, s1, sp5, p1, p1t1 real :: num, den if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (potential_density): module must be initialized') endif if(linear_eos) then do k=1,nk do j=jsd,jed do i=isd,ied potential_density(i,j,k) = rho0 - alpha_linear_eos*theta(i,j,k) + beta_linear_eos*salinity(i,j,k) enddo enddo enddo else p1 = pressure if(p1 > 0.0) then do k=1,nk do j=jsd,jed do i=isd,ied t1 = theta(i,j,k) t2 = t1*t1 s1 = salinity(i,j,k) sp5 = sqrt(s1) p1t1 = p1*t1 num = a0 + t1*(a1 + t1*(a2+a3*t1) ) & + s1*(a4 + a5*t1 + a6*s1) & + p1*(a7 + a8*t2 + a9*s1 + p1*(a10+a11*t2)) den = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) & + p1*(b10 + p1t1*(b11*t2 + b12*p1)) potential_density(i,j,k) = num/(epsln+den) enddo enddo enddo elseif(p1==0.0) then ! for sigma_0 do k=1,nk do j=jsd,jed do i=isd,ied t1 = theta(i,j,k) t2 = t1*t1 s1 = salinity(i,j,k) sp5 = sqrt(s1) num = a0 + t1*(a1 + t1*(a2+a3*t1) ) & + s1*(a4 + a5*t1 + a6*s1) den = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) potential_density(i,j,k) = num/(epsln+den) enddo enddo enddo elseif(p1 < 0.0) then call mpp_error(FATAL, & '==>Error in ocean_density_mod: potential density at pressure < 0 is not defined') endif ! endif for value of pressure endif ! endif for linear_eos end function potential_density ! NAME="potential_density" !####################################################################### ! ! ! ! Compute density as a function of surface salinity, surface theta, ! and insitu sea pressure. ! ! Note that pressure here is ! sea pressure = absolute pressure - press_standard (dbars) ! ! For use in KPP mixed layer scheme ! ! function density_sfc (salinity, theta, press) real, intent(in), dimension(isd:,jsd:,:) :: salinity real, intent(in), dimension(isd:,jsd:,:) :: theta real, intent(in), dimension(isd:,jsd:,:) :: press real, dimension(isd:ied,jsd:jed,nk) :: density_sfc integer :: i, j, k real :: t1, t2, s1, sp5, p1, p1t1 real :: num, den if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_sfc): module must be initialized') endif if(linear_eos) then do k=1,nk do j=jsd,jed do i=isd,ied density_sfc(i,j,k) = rho0 - alpha_linear_eos*theta(i,j,1) + beta_linear_eos*salinity(i,j,1) enddo enddo enddo else do k=1,nk do j=jsd,jed do i=isd,ied t1 = theta(i,j,1) t2 = t1*t1 s1 = salinity(i,j,1) sp5 = sqrt(s1) p1 = press(i,j,k) - press_standard p1t1 = p1*t1 num = a0 + t1*(a1 + t1*(a2+a3*t1) ) & + s1*(a4 + a5*t1 + a6*s1) & + p1*(a7 + a8*t2 + a9*s1 + p1*(a10+a11*t2)) den = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) & + p1*(b10 + p1t1*(b11*t2 + b12*p1)) density_sfc(i,j,k) = num/(epsln + den) enddo enddo enddo endif end function density_sfc ! NAME="density_sfc" !####################################################################### ! ! ! ! Compute density at a single model grid point. ! ! Note that pressure here is ! ! sea pressure = absolute pressure - press_standard (dbars) ! ! ! function density_point (s1, t1, p1_dbars) real, intent(in) :: s1, t1, p1_dbars real :: t2, sp5, p1, p1t1 real :: num, den real :: density_point if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_point): module must be initialized') endif if(linear_eos) then density_point = rho0 - alpha_linear_eos*t1 + beta_linear_eos*s1 else t2 = t1*t1 sp5 = sqrt(s1) p1 = p1_dbars - press_standard p1t1 = p1*t1 num = a0 + t1*(a1 + t1*(a2+a3*t1)) & + s1*(a4 + a5*t1 + a6*s1) & + p1*(a7 + a8*t2 + a9*s1 + p1*(a10+a11*t2)) den = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4 ))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) & + p1*(b10 + p1t1*(b11*t2 + b12*p1)) density_point = num/(epsln+den) endif end function density_point ! NAME="density_point" !####################################################################### ! ! ! ! Compute partial derivative of density with respect to potential ! temperature and with respect to salinity. Hold pressure constant. ! ! Pressure here is ! ! sea pressure = absolute press - press_standard (dbars) ! ! ! subroutine density_derivs_field (rho, salinity, theta, press, Time, & density_theta, density_salinity, density_press) type(ocean_time_type), intent(in) :: Time real, dimension(isd:,jsd:,:), intent(in) :: rho real, dimension(isd:,jsd:,:), intent(in) :: salinity real, dimension(isd:,jsd:,:), intent(in) :: theta real, dimension(isd:,jsd:,:), intent(in) :: press real, dimension(isd:,jsd:,:), intent(inout) :: density_theta real, dimension(isd:,jsd:,:), intent(inout) :: density_salinity real, dimension(isd:,jsd:,:), intent(inout) :: density_press integer :: i, j, k real :: t1, t2, s1, sp5, p1, p1t1 real :: dnum_dtheta, dden_dtheta real :: dnum_dsalinity, dden_dsalinity real :: dnum_dpress, dden_dpress if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_derivs_field): module must be initialized') endif if(linear_eos) then do k=1,nk do j=jsd,jed do i=isd,ied density_theta(i,j,k) = -alpha_linear_eos density_salinity(i,j,k) = beta_linear_eos density_press(i,j,k) = 0.0 enddo enddo enddo else do k=1,nk do j=jsd,jed do i=isd,ied t1 = theta(i,j,k) t2 = t1*t1 s1 = salinity(i,j,k) sp5 = sqrt(s1) p1 = press(i,j,k) - press_standard p1t1 = p1*t1 dnum_dtheta = a1 + t1*(two_a2 + three_a3*t1) & + a5*s1 & + p1t1*(two_a8 + two_a11*p1) dden_dtheta = b1 + t1*(two_b2 + t1*(three_b3 + four_b4*t1)) & + s1*(b6 + t1*(three_b7*t1 + two_b9*sp5)) & + p1*p1*(three_b11*t2 + b12*p1) dnum_dsalinity = a4 + a5*t1 + two_a6*s1 + a9*p1 dden_dsalinity = b5 + t1*(b6 + b7*t2) + sp5*(onep5_b8 + onep5_b9*t2) dnum_dpress = a7 + a9*s1 + two_a10*p1 + t2*(a8 + two_a11*p1) dden_dpress = b10 + p1*t1*(two_b11*t2 + three_b12*p1) density_theta(i,j,k) = denominator_r(i,j,k)*(dnum_dtheta - rho(i,j,k)*dden_dtheta) density_salinity(i,j,k) = denominator_r(i,j,k)*(dnum_dsalinity - rho(i,j,k)*dden_dsalinity) density_press(i,j,k) = denominator_r(i,j,k)*(dnum_dpress - rho(i,j,k)*dden_dpress)*c2dbars enddo enddo enddo endif if (id_drhodtheta > 0) used = send_data (id_drhodtheta, density_theta(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) if (id_drhodsalt > 0) used = send_data (id_drhodsalt, density_salinity(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) if (id_drhodpress > 0) used = send_data (id_drhodpress, density_press(:,:,:),& Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) if (id_sound_speed2 > 0) then wrk1(:,:,:) = 0.0 do k=1,nk do j=jsd,jed do i=isd,ied if(density_press(i,j,k) /= 0.0) then wrk1(i,j,k) = 1.0/density_press(i,j,k) endif enddo enddo enddo used = send_data (id_sound_speed2, wrk1(:,:,:),& Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif end subroutine density_derivs_field ! NAME="density_derivs_field" !####################################################################### ! ! ! ! Compute cabbeling and thermobaricity parameters, as defined in ! McDougall (1987). ! ! Pressure here is ! sea pressure = absolute press - press_standard (dbars) ! ! ! subroutine cabbeling_thermobaricity(rho, salinity, theta, press, Time, & density_theta, density_salinity, density_press) real, dimension(isd:,jsd:,:), intent(in) :: rho real, dimension(isd:,jsd:,:), intent(in) :: salinity real, dimension(isd:,jsd:,:), intent(in) :: theta real, dimension(isd:,jsd:,:), intent(in) :: press type(ocean_time_type), intent(in) :: Time real, dimension(isd:,jsd:,:), intent(in) :: density_theta real, dimension(isd:,jsd:,:), intent(in) :: density_salinity real, dimension(isd:,jsd:,:), intent(in) :: density_press integer :: i, j, k real :: t1, t2, s1, sp5, spm5, p1, p2, p1t1 real :: rhotheta_rhosalinity real :: rho_inv real :: d2rho_dtheta2, d2rho_dsalin2, d2rho_dsalin_dtheta real :: d2rho_dsalin_dpress, d2rho_dtheta_dpress real :: dden_dtheta, dden_dsalinity, dden_dpress real :: d2num_dtheta2, d2num_dsalin2, d2num_dtheta_dsalin real :: d2num_dsalin_dpress, d2num_dtheta_dpress real :: d2den_dtheta2, d2den_dsalin2, d2den_dsalin_dtheta real :: d2den_dsalin_dpress, d2den_dtheta_dpress if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (cabbeling_thermobaricity): module must be initialized') endif wrk1(:,:,:) = 0.0 ! cabbeling parameter wrk2(:,:,:) = 0.0 ! thermobaricity parameter if(.not. linear_eos) then do k=1,nk do j=jsd,jed do i=isd,ied t1 = theta(i,j,k) t2 = t1*t1 s1 = salinity(i,j,k) sp5 = sqrt(s1) p1 = press(i,j,k) - press_standard p2 = p1*p1 p1t1 = p1*t1 if(s1 > 0.0) then spm5 = 1.0/sp5 else spm5 = 0.0 endif rhotheta_rhosalinity = Grd%tmask(i,j,k)*density_theta(i,j,k)/(epsln+density_salinity(i,j,k)) dden_dtheta = b1 + t1*(two_b2 + t1*(three_b3 + four_b4*t1)) & + s1*(b6 + t1*(three_b7*t1 + two_b9*sp5)) & + p1*p1*(three_b11*t2 + b12*p1) dden_dsalinity = b5 + t1*(b6 + b7*t2) + sp5*(onep5_b8 + onep5_b9*t2) dden_dpress = b10 + p1*t1*(two_b11*t2 + three_b12*p1) d2num_dtheta2 = two_a2 + six_a3*t1 + two_a8*p1 + two_a11*p2 d2num_dsalin2 = two_a6 d2num_dtheta_dsalin = a5 d2num_dsalin_dpress = a9 d2num_dtheta_dpress = two_a8*t1 + four_a11*p1*t1 d2den_dtheta2 = two_b2 + six_b3*t1 + twelve_b4*t2 & + six_b7*s1*t1 + two_b9*s1*sp5 + six_b11*p2*t1 d2den_dsalin2 = .75*spm5*(b8 + b9*t2) d2den_dsalin_dtheta = b6 + three_b7*t2 + three_b9*sp5*t1 d2den_dsalin_dpress = 0.0 d2den_dtheta_dpress = six_b11*p1*t2 + three_b12*p2 d2rho_dtheta2 = denominator_r(i,j,k) & *(d2num_dtheta2-2.0*density_theta(i,j,k)*dden_dtheta-rho(i,j,k)*d2den_dtheta2) d2rho_dsalin2 = denominator_r(i,j,k) & *(d2num_dsalin2-2.0*density_salinity(i,j,k)*dden_dsalinity-rho(i,j,k)*d2den_dsalin2) d2rho_dsalin_dtheta = denominator_r(i,j,k) & *( d2num_dtheta_dsalin & -density_salinity(i,j,k)*dden_dtheta & -density_theta(i,j,k)*dden_dsalinity & -rho(i,j,k)*d2den_dsalin_dtheta) d2rho_dsalin_dpress = denominator_r(i,j,k) & *( d2den_dsalin_dpress & -density_press(i,j,k)*dden_dsalinity & -density_salinity(i,j,k)*dden_dpress & -rho(i,j,k)*d2den_dsalin_dpress) d2rho_dtheta_dpress = denominator_r(i,j,k) & *( d2den_dtheta_dpress & -density_press(i,j,k)*dden_dtheta & -density_theta(i,j,k)*dden_dpress & -rho(i,j,k)*d2den_dtheta_dpress) rho_inv = Grd%tmask(i,j,k)/(rho(i,j,k) + epsln) wrk1(i,j,k) = -rho_inv* & ( d2rho_dtheta2 & -2.0*d2rho_dsalin_dtheta*rhotheta_rhosalinity & +d2rho_dsalin2*rhotheta_rhosalinity**2 ) wrk2(i,j,k) = -rho_inv*(d2rho_dtheta_dpress-d2rho_dsalin_dpress*rhotheta_rhosalinity) enddo enddo enddo endif if(id_cabbeling > 0) then used = send_data (id_cabbeling, wrk1(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:),& is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif if(id_thermobaricity > 0) then used = send_data (id_thermobaricity, wrk2(:,:,:),& Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif end subroutine cabbeling_thermobaricity ! NAME="cabbeling_thermobaricity" !####################################################################### ! ! ! ! Compute partial derivative of density with respect to potential ! temperature and with respect to salinity. Hold pressure constant. ! ! Pressure here is sea pressure = absolute press - press_standard ! ! ! subroutine density_derivs_level (rho, salinity, theta, press, Time, klevel, & density_theta, density_salinity, density_press) type(ocean_time_type), intent(in) :: Time real, dimension(isd:,jsd:), intent(in) :: rho real, dimension(isd:,jsd:), intent(in) :: salinity real, dimension(isd:,jsd:), intent(in) :: theta real, dimension(isd:,jsd:), intent(in) :: press integer, intent(in) :: klevel real, dimension(isd:,jsd:), intent(inout) :: density_theta real, dimension(isd:,jsd:), intent(inout) :: density_salinity real, dimension(isd:,jsd:), intent(inout) :: density_press integer :: i, j real :: t1, t2, s1, sp5, p1, p1t1 real :: dnum_dtheta, dden_dtheta real :: dnum_dsalinity, dden_dsalinity real :: dnum_dpress, dden_dpress if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_derivs_level): module must be initialized') endif if(linear_eos) then do j=jsd,jed do i=isd,ied density_theta(i,j) = -alpha_linear_eos density_salinity(i,j) = beta_linear_eos density_press(i,j) = 0.0 enddo enddo else do j=jsd,jed do i=isd,ied t1 = theta(i,j) t2 = t1*t1 s1 = salinity(i,j) sp5 = sqrt(s1) p1 = press(i,j) - press_standard p1t1 = p1*t1 dnum_dtheta = a1 + t1*(two_a2 + three_a3*t1) & + a5*s1 & + p1t1*(two_a8 + two_a11*p1) dden_dtheta = b1 + t1*(two_b2 + t1*(three_b3 + four_b4*t1)) & + s1*(b6 + t1*(three_b7*t1 + two_b9*sp5)) & + p1*p1*(three_b11*t2 + b12*p1) dnum_dsalinity = a4 + a5*t1 + two_a6*s1 + a9*p1 dden_dsalinity = b5 + t1*(b6 + b7*t2) + sp5*(onep5_b8 + onep5_b9*t2) dnum_dpress = a7 + a9*s1 + two_a10*p1 + t2*(a8 + two_a11*p1) dden_dpress = b10 + p1*t1*(two_b11*t2 + three_b12*p1) density_theta(i,j) = denominator_r(i,j,klevel)*(dnum_dtheta - rho(i,j)*dden_dtheta) density_salinity(i,j) = denominator_r(i,j,klevel)*(dnum_dsalinity - rho(i,j)*dden_dsalinity) density_press(i,j) = denominator_r(i,j,klevel)*(dnum_dpress - rho(i,j)*dden_dpress) enddo enddo endif end subroutine density_derivs_level ! NAME="density_derivs_level" !####################################################################### ! ! ! ! Compute partial derivative of density with respect to potential ! temperature and with respect to salinity. Do so here for a point. ! ! Pressure here is ! ! sea pressure = absolute pressure - press_standard (dbars) ! ! ! subroutine density_derivs_point (rho, salinity, theta, press,& density_theta, density_salinity, density_press) real, intent(in) :: rho, salinity, theta, press real, intent(out) :: density_theta, density_salinity,density_press real :: t1, t2, s1, sp5, p1, p1t1 real :: dnum_dtheta, dden_dtheta real :: dnum_dsalinity, dden_dsalinity real :: dnum_dpress, dden_dpress real :: density_point, denrecip if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_derivs_point): module must be initialized') endif if(linear_eos) then density_theta = -alpha_linear_eos density_salinity = beta_linear_eos density_press = 0.0 else t1 = theta t2 = t1*t1 s1 = salinity sp5 = sqrt(s1) p1 = press - press_standard p1t1 = p1*t1 density_point = b0 + t1*(b1 + t1*(b2 + t1*(b3 + t1*b4 ))) & + s1*(b5 + t1*(b6 + b7*t2) + sp5*(b8 + b9*t2)) & + p1*(b10 + p1t1*(b11*t2 + b12*p1)) denrecip = 1.0/(density_point + epsln) dnum_dtheta = a1 + t1*(2.0*a2 + 3.0*a3*t1) & + a5*s1 & + 2.0*p1t1*(a8 + a11*p1) dden_dtheta = b1 + t1*(2.0*b2 + t1*(3.0*b3 + 4.0*b4*t1)) & + s1*(b6 + t1*(3.0*b7*t1 + 2.0*b9*sp5)) & + p1*p1*(3.0*b11*t2 + b12*p1) dnum_dsalinity = a4 + a5*t1 + two_a6*s1 + a9*p1 dden_dsalinity = b5 + t1*(b6 + b7*t2) + sp5*(onep5_b8 + onep5_b9*t2) dnum_dpress = a7 + a9*s1 + two_a10*p1 + t2*(a8 + two_a11*p1) dden_dpress = b10 + p1*t1*(two_b11*t2 + three_b12*p1) density_theta = denrecip*(dnum_dtheta - rho*dden_dtheta) density_salinity = denrecip*(dnum_dsalinity - rho*dden_dsalinity) density_press = denrecip*(dnum_dpress - rho*dden_dpress) endif end subroutine density_derivs_point ! NAME="density_derivs_point" !####################################################################### ! ! ! ! rho(k)-rho(k+1) for all i,j with both temperatures referenced to the ! deeper pressure depth. ! ! Of use for KPP scheme. ! ! function density_delta_z (rho_initial, salinity, theta, press) real, intent(in), dimension(isd:,jsd:,:) :: rho_initial real, intent(in), dimension(isd:,jsd:,:) :: salinity real, intent(in), dimension(isd:,jsd:,:) :: theta real, intent(in), dimension(isd:,jsd:,:) :: press real, dimension(isd:ied,jsd:jed,nk) :: density_delta_z integer :: k if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_delta_z): module must be initialized') endif do k=1,nk-1 wrk1(:,:,k) = press(:,:,k+1) enddo wrk1(:,:,nk) = press(:,:,nk) wrk2(:,:,:) = density(salinity(:,:,:), theta(:,:,:), wrk1(:,:,:)) do k=1,nk-1 density_delta_z(:,:,k) = (wrk2(:,:,k) - rho_initial(:,:,k+1))*Grd%tmask(:,:,k+1) enddo density_delta_z(:,:,nk) = (wrk2(:,:,nk) - rho_initial(:,:,nk))*Grd%tmask(:,:,nk) end function density_delta_z ! NAME="density_delta_z" !####################################################################### ! ! ! ! rho(1)-rho(k+1) for all i,j. ! ! Of use for KPP scheme. ! ! function density_delta_sfc (rho_initial, salinity, theta, press) real, intent(in), dimension(isd:,jsd:,:) :: rho_initial real, intent(in), dimension(isd:,jsd:,:) :: salinity real, intent(in), dimension(isd:,jsd:,:) :: theta real, intent(in), dimension(isd:,jsd:,:) :: press real, dimension(isd:ied,jsd:jed,nk) :: density_delta_sfc integer :: k if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (density_delta_sfc): module must be initialized') endif do k=1,nk-1 wrk1(:,:,k) = press(:,:,k+1) enddo wrk1(:,:,nk) = press(:,:,nk) wrk2(:,:,:) = density_sfc(salinity, theta, wrk1) do k=1,nk-1 density_delta_sfc(:,:,k) = (wrk2(:,:,k) - rho_initial(:,:,k+1))*Grd%tmask(:,:,k+1) enddo density_delta_sfc(:,:,nk) = (wrk2(:,:,nk) - rho_initial(:,:,nk))*Grd%tmask(:,:,nk) end function density_delta_sfc ! NAME="density_delta_sfc" !####################################################################### ! ! ! ! Diagnose the buoyancy frequency, both at T-points and at ! vertical interfaces of T-cells. The algorithm follows that ! used in subroutine diagnose_wdianeutral. ! ! Author: Stephen.Griffies@noaa.gov ! ! ! subroutine compute_buoyfreq(Time, Thickness, salinity, theta, Dens) type(ocean_time_type), intent(in) :: Time type(ocean_thickness_type), intent(in) :: Thickness real, dimension(isd:,jsd:,:), intent(in) :: salinity real, dimension(isd:,jsd:,:), intent(in) :: theta type(ocean_density_type), intent(inout) :: Dens integer :: i,j,k,kp1,kbot,m,n integer :: tau real :: drhodz_prev, tmpdrhodz, drhodzr if (.not. module_is_initialized) then call mpp_error(FATAL, & '==>Error from ocean_tracer_diag (compute_buoyfreq): module needs initialization') endif tau = Time%tau wrk1(:,:,:) = 0.0 wrk2(:,:,:) = 0.0 wrk3(:,:,:) = 0.0 wrk4(:,:,:) = 0.0 ! vertical derivative of temp and salt do k=1,nk-1 kp1 = k+1 do j=jsd,jed do i=isd,ied wrk1(i,j,k) = (theta(i,j,k)-theta(i,j,kp1))/Thickness%dzwt(i,j,k) wrk2(i,j,k) = (salinity(i,j,k)-salinity(i,j,kp1))/Thickness%dzwt(i,j,k) enddo enddo enddo ! vertical derivative of neutral density. ! vanishes at the bottom of a column. do k=1,nk-1 kp1=k+1 do j=jsd,jed do i=isd,ied wrk3(i,j,k) = Dens%drhodT(i,j,k)*wrk1(i,j,k) + Dens%drhodS(i,j,k)*wrk2(i,j,k) if(abs(wrk3(i,j,k)) < epsln_drhodz) then wrk3(i,j,k) = sign(1.0,wrk3(i,j,k))*epsln_drhodz endif wrk3(i,j,k) = Grd%tmask(i,j,kp1)*wrk3(i,j,k) enddo enddo enddo ! vertically smooth drhodz; otherwise can get noisy results if(buoyfreq_smooth_vert) then do m=1,num_121_passes do j=jsd,jed do i=isd,ied drhodz_prev = onefourth*wrk3(i,j,1) kbot=Grd%kmt(i,j) if(kbot>3) then do k=2,kbot-2 tmpdrhodz = wrk3(i,j,k) wrk3(i,j,k) = drhodz_prev + onehalf*wrk3(i,j,k) + onefourth*wrk3(i,j,k+1) drhodz_prev = onefourth*tmpdrhodz enddo endif enddo enddo enddo endif ! drhodz at bottom of T-cell do k=1,nk do j=jsd,jed do i=isd,ied Dens%drhodz_wt(i,j,k) = wrk3(i,j,k) enddo enddo enddo if(id_buoyfreq2_wt > 0) then used = send_data (id_buoyfreq2_wt, -grav*rho0r*wrk3(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif if(id_drhodz_wt > 0) then used = send_data (id_drhodz_wt, wrk3(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif ! drhodz and squared buoyancy frequency at T-cell point wrk4(:,:,:) = 0.0 k=1 do j=jsd,jed do i=isd,ied Dens%drhodz_zt(i,j,k) = Dens%drhodz_wt(i,j,k) wrk4(i,j,k) = Dens%drhodz_wt(i,j,k) enddo enddo do k=2,nk do j=jsd,jed do i=isd,ied wrk4(i,j,k) = wrk3(i,j,k-1)*(Thickness%depth_zwt(i,j,k)-Thickness%depth_zt(i,j,k)) & +wrk3(i,j,k) *(Thickness%depth_zt(i,j,k) -Thickness%depth_zwt(i,j,k-1)) wrk4(i,j,k) = wrk4(i,j,k)/(epsln+Thickness%dzt(i,j,k)) Dens%drhodz_zt(i,j,k) = wrk4(i,j,k) enddo enddo enddo if(id_buoyfreq2_zt > 0) then used = send_data (id_buoyfreq2_zt, -grav*rho0r*wrk4(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif if(id_drhodz_zt > 0) then used = send_data (id_drhodz_zt, wrk4(:,:,:), & Time%model_time, rmask=Grd%tmask(:,:,:), & is_in=isc, js_in=jsc, ks_in=1, ie_in=iec, je_in=jec, ke_in=nk) endif ! dTdz and dSdz at T-cell point wrk3(:,:,:) = 0.0 wrk4(:,:,:) = 0.0 k=1 do j=jsd,jed do i=isd,ied Dens%dTdz_zt(i,j,k) = wrk1(i,j,k) Dens%dSdz_zt(i,j,k) = wrk2(i,j,k) enddo enddo do k=2,nk do j=jsd,jed do i=isd,ied wrk3(i,j,k) = wrk1(i,j,k-1)*(Thickness%depth_zwt(i,j,k)-Thickness%depth_zt(i,j,k)) & +wrk1(i,j,k) *(Thickness%depth_zt(i,j,k) -Thickness%depth_zwt(i,j,k-1)) wrk4(i,j,k) = wrk2(i,j,k-1)*(Thickness%depth_zwt(i,j,k)-Thickness%depth_zt(i,j,k)) & +wrk2(i,j,k) *(Thickness%depth_zt(i,j,k) -Thickness%depth_zwt(i,j,k-1)) wrk3(i,j,k) = wrk3(i,j,k)/(epsln+Thickness%dzt(i,j,k)) wrk4(i,j,k) = wrk4(i,j,k)/(epsln+Thickness%dzt(i,j,k)) Dens%dTdz_zt(i,j,k) = wrk3(i,j,k) Dens%dSdz_zt(i,j,k) = wrk4(i,j,k) enddo enddo enddo end subroutine compute_buoyfreq ! NAME="compute_buoyfreq" !####################################################################### ! ! ! ! ! Write density and pressure_at_depth to a restart. ! ! subroutine ocean_density_end(Time, Dens) type(ocean_time_type), intent(in) :: Time type(ocean_density_type), intent(in) :: Dens integer :: stdoutunit stdoutunit=stdout() if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (ocean_density_end): module must be initialized') endif if(.not. write_a_restart) then write(stdoutunit,'(/a)') '==>Warning from ocean_density_mod (ocean_density_end): NO restart written.' call mpp_error(WARNING,'==>Warning from ocean_density_mod (ocean_density_end): NO restart written.') return endif call ocean_density_restart(Time, Dens) write(stdoutunit,'(/a)') ' From ocean_density_mod: ending density chksums' call write_timestamp(Time%model_time) call ocean_density_chksum(Time, Dens) module_is_initialized = .FALSE. end subroutine ocean_density_end ! NAME="ocean_density_end" !####################################################################### ! ! ! Write out restart files registered through register_restart_file ! subroutine ocean_density_restart(Time, Dens, time_stamp) type(ocean_time_type), intent(in) :: Time type(ocean_density_type), intent(in) :: Dens character(len=*), intent(in), optional :: time_stamp integer :: tau, taup1 if ( .not. module_is_initialized ) then call mpp_error(FATAL, & '==>Error in ocean_density_mod (ocean_density_end): module must be initialized') endif taup1 = Time%taup1 call reset_field_pointer(Den_restart, id_restart_rho, Dens%rho(:,:,:,taup1) ) call save_restart(Den_restart, time_stamp) end subroutine ocean_density_restart ! NAME="ocean_density_restart" !####################################################################### ! ! ! ! Compute checksums for density. ! subroutine ocean_density_chksum(Time, Dens) type(ocean_time_type), intent(in) :: Time type(ocean_density_type), intent(in) :: Dens integer(i8_kind) :: chk_sum integer :: taup1 integer :: stdoutunit stdoutunit=stdout() if (.not. module_is_initialized) then call mpp_error(FATAL,& '==>Error from ocean_density_mod (ocean_density_chksum): module not yet initialized ') endif taup1 = Time%taup1 wrk1(isc:iec,jsc:jec,:) = Dens%rho(isc:iec,jsc:jec,:,taup1)*Grd%tmask(isc:iec,jsc:jec,:) chk_sum = mpp_chksum(wrk1(isc:iec,jsc:jec,:)) write(stdoutunit,*) 'chksum for rho(taup1) = ', chk_sum wrk1(isc:iec,jsc:jec,:) = Dens%pressure_at_depth(isc:iec,jsc:jec,:)*Grd%tmask(isc:iec,jsc:jec,:) chk_sum = mpp_chksum(wrk1(isc:iec,jsc:jec,:)) write(stdoutunit,*) 'chksum for pressure_at_depth = ', chk_sum wrk1(isc:iec,jsc:jec,:) = denominator_r(isc:iec,jsc:jec,:)*Grd%tmask(isc:iec,jsc:jec,:) chk_sum = mpp_chksum(wrk1(isc:iec,jsc:jec,:)) write(stdoutunit,*) 'chksum for denominator_r = ', chk_sum wrk1(isc:iec,jsc:jec,:) = Dens%drhodT(isc:iec,jsc:jec,:)*Grd%tmask(isc:iec,jsc:jec,:) chk_sum = mpp_chksum(wrk1(isc:iec,jsc:jec,:)) write(stdoutunit,*) 'chksum for drhodT = ', chk_sum wrk1(isc:iec,jsc:jec,:) = Dens%drhodS(isc:iec,jsc:jec,:)*Grd%tmask(isc:iec,jsc:jec,:) chk_sum = mpp_chksum(wrk1(isc:iec,jsc:jec,:)) write(stdoutunit,*) 'chksum for drhodS = ', chk_sum wrk1(isc:iec,jsc:jec,:) = Dens%drhodz_zt(isc:iec,jsc:jec,:)*Grd%tmask(isc:iec,jsc:jec,:) chk_sum = mpp_chksum(wrk1(isc:iec,jsc:jec,:)) write(stdoutunit,*) 'chksum for drhodz_zt = ', chk_sum end subroutine ocean_density_chksum ! NAME="ocean_density_chksum" end module ocean_density_mod