! ----------------------------------------------------------------
! GNU General Public License
! This file is a part of MOM.
!
! MOM 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; either version 2 of
! the License, or (at your option) any later version.
!
! MOM 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.
!
! For the full text of the GNU General Public License,
! write to: Free Software Foundation, Inc.,
! 675 Mass Ave, Cambridge, MA 02139, USA.
! or see: http://www.gnu.org/licenses/gpl.html
!-----------------------------------------------------------------------
!
!
! Richard D. Slater
!
!
! John P. Dunne
!
!
!
! Ocean Carbon Model Intercomparison Study II: Gas exchange coupler
!
!
!
! Implementation of routines to solve the gas fluxes at the
! ocean surface for a coupled model
! as outlined in the Biotic-HOWTO documentation,
! revision 1.7, 1999/10/05.
!
!
!
! http://www.ipsl.jussieu.fr/OCMIP/phase2/simulations/Biotic/HOWTO-Biotic.html
!
!
!
!------------------------------------------------------------------
!
! Module atmos_ocean_fluxes_mod
!
! This module will take fields from an atmospheric and an
! oceanic model and calculate ocean surface fluxes for
! CO2, O2, CFC-11 or CFC-12 as outlined in the various
! HOWTO documents at the OCMIP2 website. Multiple instances
! of a given tracer may be given, resulting in multiple
! surface fluxes. Additionally, data may be overridden at
! the individual fields, or fluxes. This could be used in
! the absence of an atmospheric or oceanic model.
!
!------------------------------------------------------------------
!
module atmos_ocean_fluxes_mod !{
!
!------------------------------------------------------------------
!
! Global definitions
!
!------------------------------------------------------------------
!
!
!----------------------------------------------------------------------
!
! Modules
!
!----------------------------------------------------------------------
!
use mpp_mod, only: stdout, stdlog, mpp_error, FATAL, mpp_sum, mpp_npes
use coupler_types_mod, only: coupler_1d_bc_type
use coupler_types_mod, only: ind_alpha, ind_csurf, ind_sc_no
use coupler_types_mod, only: ind_pcair, ind_u10, ind_psurf
use coupler_types_mod, only: ind_deposition
use coupler_types_mod, only: ind_runoff
use coupler_types_mod, only: ind_flux, ind_deltap, ind_kw
use field_manager_mod, only: fm_path_name_len, fm_string_len, fm_exists, fm_get_index
use field_manager_mod, only: fm_new_list, fm_get_current_list, fm_change_list
use field_manager_mod, only: fm_field_name_len, fm_type_name_len, fm_dump_list
use field_manager_mod, only: fm_loop_over_list
use fm_util_mod, only: fm_util_default_caller
use fm_util_mod, only: fm_util_get_length
use fm_util_mod, only: fm_util_set_value, fm_util_set_good_name_list, fm_util_set_no_overwrite
use fm_util_mod, only: fm_util_set_caller, fm_util_reset_good_name_list, fm_util_reset_no_overwrite
use fm_util_mod, only: fm_util_reset_caller, fm_util_get_string_array, fm_util_check_for_bad_fields
use fm_util_mod, only: fm_util_get_string, fm_util_get_real_array, fm_util_get_real, fm_util_get_integer
use fm_util_mod, only: fm_util_get_logical, fm_util_get_logical_array
!
!----------------------------------------------------------------------
!
! force all variables to be "typed"
!
!----------------------------------------------------------------------
!
implicit none
!
!----------------------------------------------------------------------
!
! Make all routines and variables private by default
!
!----------------------------------------------------------------------
!
private
!
!----------------------------------------------------------------------
!
! Public routines
!
!----------------------------------------------------------------------
!
public :: atmos_ocean_fluxes_calc
public :: atmos_ocean_fluxes_init
public :: aof_set_coupler_flux
!
!----------------------------------------------------------------------
!
! Public parameters
!
!----------------------------------------------------------------------
!
!
!----------------------------------------------------------------------
!
! Public types
!
!----------------------------------------------------------------------
!
!
!----------------------------------------------------------------------
!
! Public variables
!
!----------------------------------------------------------------------
!
!
!----------------------------------------------------------------------
!
! Private routines
!
!----------------------------------------------------------------------
!
!
!----------------------------------------------------------------------
!
! Private parameters
!
!----------------------------------------------------------------------
!
character(len=48), parameter :: mod_name = 'atmos_ocean_fluxes_mod'
!
!----------------------------------------------------------------------
!
! Private types
!
!----------------------------------------------------------------------
!
!
!----------------------------------------------------------------------
!
! Private variables
!
!----------------------------------------------------------------------
!
character(len=128) :: version = '$Id: atmos_ocean_fluxes.F90,v 1.1.1.2 2012-11-16 16:00:09 atrayano Exp $'
character(len=128) :: tagname = '$Name: Heracles-1_1 $'
!
!-----------------------------------------------------------------------
!
! Subroutine and function definitions
!
!-----------------------------------------------------------------------
!
contains
!#######################################################################
!
!
!
! Set the values for a coupler flux and return its index (0 on error)
!
!
function aof_set_coupler_flux(name, flux_type, implementation, atm_tr_index, param, flag, &
mol_wt, ice_restart_file, ocean_restart_file, units, caller) &
result (coupler_index) !{
implicit none
!
! Return type
!
integer :: coupler_index
!
! arguments
!
character(len=*), intent(in) :: name
character(len=*), intent(in) :: flux_type
character(len=*), intent(in) :: implementation
integer, intent(in), optional :: atm_tr_index
real, intent(in), dimension(:), optional :: param
logical, intent(in), dimension(:), optional :: flag
real, intent(in), optional :: mol_wt
character(len=*), intent(in), optional :: ice_restart_file
character(len=*), intent(in), optional :: ocean_restart_file
character(len=*), intent(in), optional :: units
character(len=*), intent(in), optional :: caller
!
! Local parameters
!
character(len=48), parameter :: sub_name = 'aof_set_coupler_flux'
!
! Local variables
!
integer :: n
integer :: length
integer :: num_parameters
integer :: outunit
character(len=fm_path_name_len) :: coupler_list
character(len=fm_path_name_len) :: current_list
character(len=fm_string_len) :: flux_type_test
character(len=fm_string_len) :: implementation_test
character(len=256) :: error_header
character(len=256) :: warn_header
character(len=256) :: note_header
character(len=128) :: flux_list
character(len=128) :: caller_str
character(len=fm_string_len), pointer, dimension(:) :: good_list => NULL()
character(len=256) :: long_err_msg
!
! set the caller string and headers
!
if (present(caller)) then !{
caller_str = '[' // trim(caller) // ']'
else !}{
caller_str = fm_util_default_caller
endif !}
error_header = '==>Error from ' // trim(mod_name) // &
'(' // trim(sub_name) // ')' // trim(caller_str) // ':'
warn_header = '==>Warning from ' // trim(mod_name) // &
'(' // trim(sub_name) // ')' // trim(caller_str) // ':'
note_header = '==>Note from ' // trim(mod_name) // &
'(' // trim(sub_name) // ')' // trim(caller_str) // ':'
!
! check that a name is given (fatal if not)
!
if (name .eq. ' ') then !{
call mpp_error(FATAL, trim(error_header) // ' Empty name given')
endif !}
outunit = stdout()
write (outunit,*)
write (outunit,*) trim(note_header), ' Processing coupler fluxes ', trim(name)
!
! define the coupler list name
!
coupler_list = '/coupler_mod/fluxes/' // trim(name)
!
! Check whether a flux has already been set for this name, and if so, return
! the index for it (this is because the fluxes may be defined in both the atmosphere
! and ocean models) (check whether the good_list list exists, since this will
! indicate that this routine has already been called, and not just that
! the field table input has this list defined)
!
if (fm_exists('/coupler_mod/GOOD/fluxes/' // trim(name) // '/good_list')) then !{
write (outunit,*)
write (outunit,*) trim(note_header), ' Using previously defined coupler flux'
coupler_index = fm_get_index(coupler_list)
if (coupler_index .le. 0) then !{
call mpp_error(FATAL, trim(error_header) // ' Could not get coupler flux ')
endif !}
!
! allow atm_tr_index to be set here, since it will only be set from atmospheric
! PEs, and the atmospheric routines call this routine last, thus overwriting the
! current value is safe (furthermore, this is not a value which could have any meaningful
! value set from the run script.
!
if (present(atm_tr_index)) then !{
write (outunit,*) trim(note_header), ' Redefining atm_tr_index to ', atm_tr_index
call fm_util_set_value(trim(coupler_list) // '/atm_tr_index', atm_tr_index, no_create = .true., &
no_overwrite = .false., caller = caller_str)
endif !}
return
endif !}
!
! Set a new coupler flux and get its index
!
coupler_index = fm_new_list(coupler_list)
if (coupler_index .le. 0) then !{
call mpp_error(FATAL, trim(error_header) // ' Could not set coupler flux ')
endif !}
!
! Change to the new list, first saving the current list
!
current_list = fm_get_current_list()
if (current_list .eq. ' ') then !{
call mpp_error(FATAL, trim(error_header) // ' Could not get the current list')
endif !}
if (.not. fm_change_list(coupler_list)) then !{
call mpp_error(FATAL, trim(error_header) // ' Could not change to the new list')
endif !}
!
! Set the array in which to save the valid names for this list,
! used later for a consistency check. This is used in the fm_util_set_value
! routines to make the list of valid values
!
call fm_util_set_good_name_list('/coupler_mod/GOOD/fluxes/' // trim(name) // '/good_list')
!
! Set other defaults for the fm_util_set_value routines
!
call fm_util_set_no_overwrite(.true.)
call fm_util_set_caller(caller_str)
!
! Set various values to given values, or to defaults if not given
!
if (flux_type .eq. ' ') then !{
call mpp_error(FATAL, trim(error_header) // ' Blank flux_type given')
else !}{
if (fm_exists('/coupler_mod/types/' // trim(flux_type))) then !{
call fm_util_set_value('flux_type', flux_type)
!
! check that the flux_type that we will use (possibly given from the field_table)
! is defined
!
flux_type_test = fm_util_get_string('flux_type', scalar = .true.)
if (.not. fm_exists('/coupler_mod/types/' // trim(flux_type_test))) then !{
call mpp_error(FATAL, trim(error_header) // ' Undefined flux_type given from field_table: ' // trim(flux_type_test))
endif !}
else !}{
call mpp_error(FATAL, trim(error_header) // ' Undefined flux_type given as argument to the subroutine: ' // trim(flux_type))
endif !}
endif !}
if (implementation .eq. ' ') then !{
call mpp_error(FATAL, trim(error_header) // ' Blank flux_type given')
else !}{
if (fm_exists('/coupler_mod/types/' // trim(flux_type) // '/implementation/' // trim(implementation))) then !{
call fm_util_set_value('implementation', implementation)
!
! check that the flux_type/implementation that we will use
! (both possibly given from the field_table) is defined
!
implementation_test = fm_util_get_string('implementation', scalar = .true.)
if (.not. fm_exists('/coupler_mod/types/' // trim(flux_type_test) // '/implementation/' // trim(implementation_test))) then !{
if (flux_type .eq. flux_type_test) then
if (implementation .eq. implementation_test) then
call mpp_error(FATAL, trim(error_header) // ' Should not get here, as it is tested for above')
else
call mpp_error(FATAL, trim(error_header) // &
' Undefined flux_type/implementation (implementation given from field_table): ' // &
trim(flux_type_test) // '/implementation/' // trim(implementation_test))
endif
else
if (implementation .eq. implementation_test) then
long_err_msg = 'Undefined flux_type/implementation (flux_type given from field_table): '
long_err_msg = long_err_msg // trim(flux_type_test) // '/implementation/' // trim(implementation_test)
call mpp_error(FATAL, trim(error_header) // long_err_msg)
else
long_err_msg = ' Undefined flux_type/implementation (both given from field_table): '
long_err_msg = long_err_msg // trim(flux_type_test) // '/implementation/' // trim(implementation_test)
call mpp_error(FATAL, trim(error_header) // long_err_msg)
endif
endif
endif !}
else !}{
call mpp_error(FATAL, trim(error_header) // ' Undefined flux_type/implementation given as argument to the subroutine: ' // &
trim(flux_type) // '/implementation/' // trim(implementation))
endif !}
endif !}
if (present(atm_tr_index)) then !{
call fm_util_set_value('atm_tr_index', atm_tr_index)
else !}{
call fm_util_set_value('atm_tr_index', 0)
endif !}
if (present(mol_wt)) then !{
call fm_util_set_value('mol_wt', mol_wt)
else !}{
call fm_util_set_value('mol_wt', 0.0)
endif !}
if (present(ice_restart_file)) then !{
call fm_util_set_value('ice_restart_file', ice_restart_file)
else !}{
call fm_util_set_value('ice_restart_file', 'ice_coupler_fluxes.res.nc')
endif !}
if (present(ocean_restart_file)) then !{
call fm_util_set_value('ocean_restart_file', ocean_restart_file)
else !}{
call fm_util_set_value('ocean_restart_file', 'ocean_coupler_fluxes.res.nc')
endif !}
if (present(param)) then !{
num_parameters = fm_util_get_integer('/coupler_mod/types/' // &
trim(fm_util_get_string('flux_type', scalar = .true.)) // '/implementation/' // &
trim(fm_util_get_string('implementation', scalar = .true.)) // '/num_parameters', scalar = .true.)
length = min(size(param(:)),num_parameters)
if (length .ne. num_parameters) then !{
write (outunit,*) trim(note_header), ' Number of parameters provided for ', trim(name), ' does not match the'
write (outunit,*) 'number of parameters required (', size(param(:)), ' != ', num_parameters, ').'
write (outunit,*) 'This could be an error, or more likely is just a result of the implementation being'
write (outunit,*) 'overridden by the field table input'
endif !}
if (length .gt. 0) then !{
call fm_util_set_value('param', param(1:length), length)
else !}{
call fm_util_set_value('param', 'null', index = 0)
endif !}
else !}{
call fm_util_set_value('param', 'null', index = 0)
endif !}
if (present(flag)) then !{
call fm_util_set_value('flag', flag, size(flag(:)))
else !}{
call fm_util_set_value('flag', .false., index = 0)
endif !}
flux_list = '/coupler_mod/types/' // trim(flux_type) // '/'
if (present(units)) then !{
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'flux/name', index = ind_flux)) // '-units', units)
else !}{
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'flux/name', index = ind_flux)) // '-units', &
fm_util_get_string(trim(flux_list) // 'flux/units', index = ind_flux))
endif !}
do n = 1, fm_util_get_length(trim(flux_list) // 'flux/name') !{
if (n .ne. ind_flux) then !{
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'flux/name', index = n)) // '-units', &
fm_util_get_string(trim(flux_list) // 'flux/units', index = n))
endif !}
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'flux/name', index = n)) // '-long_name', &
fm_util_get_string(trim(flux_list) // 'flux/long_name', index = n))
enddo !} n
do n = 1, fm_util_get_length(trim(flux_list) // 'atm/name') !{
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'atm/name', index = n)) // '-units', &
fm_util_get_string(trim(flux_list) // 'atm/units', index = n))
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'atm/name', index = n)) // '-long_name', &
fm_util_get_string(trim(flux_list) // 'atm/long_name', index = n))
enddo !} n
do n = 1, fm_util_get_length(trim(flux_list) // 'ice/name') !{
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'ice/name', index = n)) // '-units', &
fm_util_get_string(trim(flux_list) // 'ice/units', index = n))
call fm_util_set_value(trim(fm_util_get_string(trim(flux_list) // 'ice/name', index = n)) // '-long_name', &
fm_util_get_string(trim(flux_list) // 'ice/long_name', index = n))
enddo !} n
!
! Reset the defaults for the fm_util_set_value calls
!
call fm_util_reset_good_name_list
call fm_util_reset_no_overwrite
call fm_util_reset_caller
!
! Change back to the saved current list
!
if (.not. fm_change_list(current_list)) then !{
call mpp_error(FATAL, trim(error_header) // ' Could not change back to ' // trim(current_list))
endif !}
!
! Check for any errors in the number of fields in this list
!
if (caller_str .eq. ' ') then !{
caller_str = trim(mod_name) // '(' // trim(sub_name) // ')'
endif !}
good_list => fm_util_get_string_array('/coupler_mod/GOOD/fluxes/' // trim(name) // '/good_list', &
caller = caller_str)
if (associated(good_list)) then !{
call fm_util_check_for_bad_fields(trim(coupler_list), good_list, caller = caller_str)
deallocate(good_list)
else !}{
call mpp_error(FATAL, trim(error_header) // ' Empty "' // trim(name) // '" list')
endif !}
return
end function aof_set_coupler_flux !}
! NAME="aof_set_coupler_flux"
!#######################################################################
!
!
!
! Initialize gas flux structures
!
!
subroutine atmos_ocean_fluxes_init(gas_fluxes, gas_fields_atm, gas_fields_ice) !{
implicit none
!
!-----------------------------------------------------------------------
! arguments
!-----------------------------------------------------------------------
!
type(coupler_1d_bc_type), intent(inout) :: gas_fluxes
type(coupler_1d_bc_type), intent(inout) :: gas_fields_atm
type(coupler_1d_bc_type), intent(inout) :: gas_fields_ice
!
!-----------------------------------------------------------------------
! local parameters
!-----------------------------------------------------------------------
!
character(len=64), parameter :: sub_name = 'atmos_ocean_fluxes_init'
character(len=256), parameter :: error_header = &
'==>Error from ' // trim(mod_name) // '(' // trim(sub_name) // '):'
character(len=256), parameter :: warn_header = &
'==>Warning from ' // trim(mod_name) // '(' // trim(sub_name) // '):'
character(len=256), parameter :: note_header = &
'==>Note from ' // trim(mod_name) // '(' // trim(sub_name) // '):'
!
!-----------------------------------------------------------------------
! local variables
!-----------------------------------------------------------------------
!
integer :: num_parameters
integer :: num_flags
integer :: n
integer :: m
character(len=128) :: caller_str
character(len=fm_type_name_len) :: typ
character(len=fm_field_name_len) :: name
integer :: ind
integer :: outunit
integer :: total_fluxes
character(len=8) :: string
character(len=128) :: error_string
character(len=128) :: flux_list
logical, save :: initialized = .false.
!
! =====================================================================
! begin executable code
! =====================================================================
!
!
! don't execute if already called
!
if (initialized) then !{
return
endif !}
initialized = .true.
outunit = stdout()
!write (outunit,*)
!write (outunit,*) 'Dumping field manager tree'
!if (.not. fm_dump_list('/', recursive = .true.)) then !{
!call mpp_error(FATAL, trim(error_header) // ' Problem dumping field manager tree')
!endif !}
caller_str = trim(mod_name) // '(' // trim(sub_name) // ')'
!
! Set other defaults for the fm_util_set_value routines
!
call fm_util_set_no_overwrite(.true.)
call fm_util_set_caller(caller_str)
!
! determine the number of flux fields
!
gas_fluxes%num_bcs = fm_util_get_length('/coupler_mod/fluxes/')
gas_fields_atm%num_bcs = gas_fluxes%num_bcs
gas_fields_ice%num_bcs = gas_fluxes%num_bcs
if (gas_fluxes%num_bcs .lt. 0) then !{
call mpp_error(FATAL, trim(error_header) // ' Could not get number of fluxes')
elseif (gas_fluxes%num_bcs .eq. 0) then !}{
write (outunit,*) trim(note_header), ' No gas fluxes'
return
else !}{
write (outunit,*) trim(note_header), ' Processing ', gas_fluxes%num_bcs, ' gas fluxes'
endif !}
!
! allocate the arrays
!
allocate (gas_fluxes%bc(gas_fluxes%num_bcs))
allocate (gas_fields_atm%bc(gas_fields_atm%num_bcs))
allocate (gas_fields_ice%bc(gas_fields_ice%num_bcs))
!
! loop over the input fields, setting the values in the flux_type
!
n = 0
do while (fm_loop_over_list('/coupler_mod/fluxes', name, typ, ind)) !{
if (typ .ne. 'list') then !{
call mpp_error(FATAL, trim(error_header) // ' ' // trim(name) // ' is not a list')
else !}{
n = n + 1 ! increment the array index
if (n .ne. ind) then !{
write (outunit,*) trim(warn_header), ' Flux index, ', ind, &
' does not match array index, ', n, ' for ', trim(name)
endif !}
!
! Change list to the new flux
!
if (.not. fm_change_list('/coupler_mod/fluxes/' // trim(name))) then !{
call mpp_error(FATAL, trim(error_header) // ' Problem changing to ' // trim(name))
endif !}
!
! save and check the flux_type
!
gas_fluxes%bc(n)%flux_type = fm_util_get_string('flux_type', scalar = .true.)
if (.not. fm_exists('/coupler_mod/types/' // trim(gas_fluxes%bc(n)%flux_type))) then !{
call mpp_error(FATAL, trim(error_header) // ' Undefined flux_type given for ' // &
trim(name) // ': ' // trim(gas_fluxes%bc(n)%flux_type))
endif !}
gas_fields_atm%bc(n)%flux_type = gas_fluxes%bc(n)%flux_type
gas_fields_ice%bc(n)%flux_type = gas_fluxes%bc(n)%flux_type
!
! save and check the implementation
!
gas_fluxes%bc(n)%implementation = fm_util_get_string('implementation', scalar = .true.)
if (.not. fm_exists('/coupler_mod/types/' // trim(gas_fluxes%bc(n)%flux_type) // &
'/implementation/' // trim(gas_fluxes%bc(n)%implementation))) then !{
call mpp_error(FATAL, trim(error_header) // ' Undefined implementation given for ' // &
trim(name) // ': ' // trim(gas_fluxes%bc(n)%flux_type) // '/implementation/' // &
trim(gas_fluxes%bc(n)%implementation))
endif !}
gas_fields_atm%bc(n)%implementation = gas_fluxes%bc(n)%implementation
gas_fields_ice%bc(n)%implementation = gas_fluxes%bc(n)%implementation
!
! set the flux list name
!
flux_list = '/coupler_mod/types/' // trim(gas_fluxes%bc(n)%flux_type) // '/'
!
! allocate the arrays
!
gas_fluxes%bc(n)%num_fields = fm_util_get_length(trim(flux_list) // 'flux/name')
allocate (gas_fluxes%bc(n)%field(gas_fluxes%bc(n)%num_fields))
gas_fields_atm%bc(n)%num_fields = fm_util_get_length(trim(flux_list) // 'atm/name')
allocate (gas_fields_atm%bc(n)%field(gas_fields_atm%bc(n)%num_fields))
gas_fields_ice%bc(n)%num_fields = fm_util_get_length(trim(flux_list) // 'ice/name')
allocate (gas_fields_ice%bc(n)%field(gas_fields_ice%bc(n)%num_fields))
!
! save the name and generate unique field names for Flux, Ice and Atm
!
gas_fluxes%bc(n)%name = name
do m = 1, fm_util_get_length(trim(flux_list) // 'flux/name') !{
gas_fluxes%bc(n)%field(m)%name = trim(name) // "_" // fm_util_get_string(trim(flux_list) // 'flux/name', index = m)
gas_fluxes%bc(n)%field(m)%override = .false.
gas_fluxes%bc(n)%field(m)%mean = .false.
enddo !} m
gas_fields_atm%bc(n)%name = name
do m = 1, fm_util_get_length(trim(flux_list) // 'atm/name') !{
gas_fields_atm%bc(n)%field(m)%name = trim(name) // "_" // fm_util_get_string(trim(flux_list) // 'atm/name', index = m)
gas_fields_atm%bc(n)%field(m)%override = .false.
gas_fields_atm%bc(n)%field(m)%mean = .false.
enddo !} m
gas_fields_ice%bc(n)%name = name
do m = 1, fm_util_get_length(trim(flux_list) // 'ice/name') !{
gas_fields_ice%bc(n)%field(m)%name = trim(name) // "_" // fm_util_get_string(trim(flux_list) // 'ice/name', index = m)
gas_fields_ice%bc(n)%field(m)%override = .false.
gas_fields_ice%bc(n)%field(m)%mean = .false.
enddo !} m
!
! save the units
!
do m = 1, fm_util_get_length(trim(flux_list) // 'flux/name') !{
gas_fluxes%bc(n)%field(m)%units = &
fm_util_get_string(trim(fm_util_get_string(trim(flux_list) // 'flux/name', index = m)) // '-units', scalar = .true.)
enddo !} m
do m = 1, fm_util_get_length(trim(flux_list) // 'atm/name') !{
gas_fields_atm%bc(n)%field(m)%units = &
fm_util_get_string(trim(fm_util_get_string(trim(flux_list) // 'atm/name', index = m)) // '-units')
enddo !} m
do m = 1, fm_util_get_length(trim(flux_list) // 'ice/name') !{
gas_fields_ice%bc(n)%field(m)%units = &
fm_util_get_string(trim(fm_util_get_string(trim(flux_list) // 'ice/name', index = m)) // '-units')
enddo !} m
!
! save the long names
!
do m = 1, fm_util_get_length(trim(flux_list) // 'flux/name') !{
gas_fluxes%bc(n)%field(m)%long_name = &
fm_util_get_string(trim(fm_util_get_string(trim(flux_list) // 'flux/name', index = m)) // '-long_name', scalar = .true.)
gas_fluxes%bc(n)%field(m)%long_name = trim(gas_fluxes%bc(n)%field(m)%long_name) // ' for ' // name
enddo !} m
do m = 1, fm_util_get_length(trim(flux_list) // 'atm/name') !{
gas_fields_atm%bc(n)%field(m)%long_name = &
fm_util_get_string(trim(fm_util_get_string(trim(flux_list) // 'atm/name', index = m)) // '-long_name')
gas_fields_atm%bc(n)%field(m)%long_name = trim(gas_fields_atm%bc(n)%field(m)%long_name) // ' for ' // name
enddo !} m
do m = 1, fm_util_get_length(trim(flux_list) // 'ice/name') !{
gas_fields_ice%bc(n)%field(m)%long_name = &
fm_util_get_string(trim(fm_util_get_string(trim(flux_list) // 'ice/name', index = m)) // '-long_name')
gas_fields_ice%bc(n)%field(m)%long_name = trim(gas_fields_ice%bc(n)%field(m)%long_name) // ' for ' // name
enddo !} m
!
! save the atm_tr_index
!
gas_fluxes%bc(n)%atm_tr_index = fm_util_get_integer('atm_tr_index', scalar = .true.)
!
! save the molecular weight
!
gas_fluxes%bc(n)%mol_wt = fm_util_get_real('mol_wt', scalar = .true.)
gas_fields_atm%bc(n)%mol_wt = gas_fluxes%bc(n)%mol_wt
gas_fields_ice%bc(n)%mol_wt = gas_fluxes%bc(n)%mol_wt
!
! save the ice_restart_file
!
gas_fluxes%bc(n)%ice_restart_file = fm_util_get_string('ice_restart_file', scalar = .true.)
gas_fields_atm%bc(n)%ice_restart_file = gas_fluxes%bc(n)%ice_restart_file
gas_fields_ice%bc(n)%ice_restart_file = gas_fluxes%bc(n)%ice_restart_file
!
! save the ocean_restart_file
!
gas_fluxes%bc(n)%ocean_restart_file = fm_util_get_string('ocean_restart_file', scalar = .true.)
gas_fields_atm%bc(n)%ocean_restart_file = gas_fluxes%bc(n)%ocean_restart_file
gas_fields_ice%bc(n)%ocean_restart_file = gas_fluxes%bc(n)%ocean_restart_file
!
! save the params
!
gas_fluxes%bc(n)%param => fm_util_get_real_array('param')
!
! save the flags
!
gas_fluxes%bc(n)%flag => fm_util_get_logical_array('flag')
!
! Perform some integrity checks
!
num_parameters = fm_util_get_integer(trim(flux_list) // 'implementation/' // &
trim(gas_fluxes%bc(n)%implementation) // '/num_parameters', scalar = .true.)
if (num_parameters .gt. 0) then !{
if (.not. associated(gas_fluxes%bc(n)%param)) then !{
write (error_string,'(a,i2)') ': need ', num_parameters
call mpp_error(FATAL, trim(error_header) // ' No param for ' // trim(name) // trim(error_string))
elseif (size(gas_fluxes%bc(n)%param(:)) .ne. num_parameters) then !}{
write (error_string,'(a,i2,a,i2)') ': ', size(gas_fluxes%bc(n)%param(:)), ' given, need ', num_parameters
call mpp_error(FATAL, trim(error_header) // ' Wrong number of param for ' // trim(name) // trim(error_string))
endif !}
elseif (num_parameters .eq. 0) then !}{
if (associated(gas_fluxes%bc(n)%param)) then !{
write (error_string,'(a,i3)') ' but has size of ', size(gas_fluxes%bc(n)%param(:))
call mpp_error(FATAL, trim(error_header) // ' No params needed for ' // trim(name) // trim(error_string))
endif !}
else !}{
write (error_string,'(a,i2)') ': ', num_parameters
call mpp_error(FATAL, trim(error_header) // 'Num_parameters is negative for ' // trim(name) // trim(error_string))
endif !}
num_flags = fm_util_get_integer(trim(flux_list) // '/num_flags', scalar = .true.)
if (num_flags .gt. 0) then !{
if (.not. associated(gas_fluxes%bc(n)%flag)) then !{
write (error_string,'(a,i2)') ': need ', num_flags
call mpp_error(FATAL, trim(error_header) // ' No flag for ' // trim(name) // trim(error_string))
elseif (size(gas_fluxes%bc(n)%flag(:)) .ne. num_flags) then !}{
write (error_string,'(a,i2,a,i2)') ': ', size(gas_fluxes%bc(n)%flag(:)), ' given, need ', num_flags
call mpp_error(FATAL, trim(error_header) // ' Wrong number of flag for ' // trim(name) // trim(error_string))
endif !}
elseif (num_flags .eq. 0) then !}{
if (associated(gas_fluxes%bc(n)%flag)) then !{
write (error_string,'(a,i3)') ' but has size of ', size(gas_fluxes%bc(n)%flag(:))
call mpp_error(FATAL, trim(error_header) // ' No flags needed for ' // trim(name) // trim(error_string))
endif !}
else !}{
write (error_string,'(a,i2)') ': ', num_flags
call mpp_error(FATAL, trim(error_header) // 'Num_flags is negative for ' // trim(name) // trim(error_string))
endif !}
!
! set some flags for this flux_type
!
gas_fluxes%bc(n)%use_atm_pressure = fm_util_get_logical(trim(flux_list) // '/use_atm_pressure')
gas_fields_atm%bc(n)%use_atm_pressure = gas_fluxes%bc(n)%use_atm_pressure
gas_fields_ice%bc(n)%use_atm_pressure = gas_fluxes%bc(n)%use_atm_pressure
gas_fluxes%bc(n)%use_10m_wind_speed = fm_util_get_logical(trim(flux_list) // '/use_10m_wind_speed')
gas_fields_atm%bc(n)%use_10m_wind_speed = gas_fluxes%bc(n)%use_10m_wind_speed
gas_fields_ice%bc(n)%use_10m_wind_speed = gas_fluxes%bc(n)%use_10m_wind_speed
gas_fluxes%bc(n)%pass_through_ice = fm_util_get_logical(trim(flux_list) // '/pass_through_ice')
gas_fields_atm%bc(n)%pass_through_ice = gas_fluxes%bc(n)%pass_through_ice
gas_fields_ice%bc(n)%pass_through_ice = gas_fluxes%bc(n)%pass_through_ice
endif !}
enddo !}
write (outunit,*)
write (outunit,*) 'Dumping fluxes tracer tree'
if (.not. fm_dump_list('/coupler_mod/fluxes', recursive = .true.)) then !{
call mpp_error(FATAL, trim(error_header) // ' Problem dumping fluxes tracer tree')
endif !}
!
! Check that the number of fluxes is the same on all processors
! If they are, then the sum of the number of fluxes across all processors
! should equal to the number of fluxes on each processor times the number of processors
!
total_fluxes = gas_fluxes%num_bcs
call mpp_sum(total_fluxes)
if (total_fluxes .ne. mpp_npes() * gas_fluxes%num_bcs) then !{
write (string, '(i4)') gas_fluxes%num_bcs
call mpp_error(FATAL, trim(error_header) // &
' Number of fluxes does not match across the processors: ' // trim(string) // ' fluxes')
endif !}
!
! Reset the defaults for the fm_util_set_value calls
!
call fm_util_reset_no_overwrite
call fm_util_reset_caller
return
end subroutine atmos_ocean_fluxes_init !}
! NAME="atmos_ocean_fluxes_init"
!#######################################################################
!
!
!
! Calculate the ocean gas fluxes. Units should be mol/m^2/s, upward flux is positive.
!
!
subroutine atmos_ocean_fluxes_calc(gas_fields_atm, gas_fields_ice, &
gas_fluxes, seawater) !{
!
!-----------------------------------------------------------------------
! modules (have to come first)
!-----------------------------------------------------------------------
!
implicit none
!
!-----------------------------------------------------------------------
! arguments
!-----------------------------------------------------------------------
!
type(coupler_1d_bc_type), intent(in) :: gas_fields_atm
type(coupler_1d_bc_type), intent(in) :: gas_fields_ice
type(coupler_1d_bc_type), intent(inout) :: gas_fluxes
real, intent(in), dimension(:) :: seawater
!
!-----------------------------------------------------------------------
! local parameters
!-----------------------------------------------------------------------
!
character(len=64), parameter :: sub_name = 'atmos_ocean_fluxes_calc'
character(len=256), parameter :: error_header = &
'==>Error from ' // trim(mod_name) // '(' // trim(sub_name) // '):'
character(len=256), parameter :: warn_header = &
'==>Warning from ' // trim(mod_name) // '(' // trim(sub_name) // '):'
character(len=256), parameter :: note_header = &
'==>Note from ' // trim(mod_name) // '(' // trim(sub_name) // '):'
!
!-----------------------------------------------------------------------
! local variables
!-----------------------------------------------------------------------
!
integer :: n
integer :: i
integer :: length
real, dimension(:), allocatable :: kw
real, dimension(:), allocatable :: cair
character(len=128) :: error_string
real, parameter :: epsln=1.0e-30
real, parameter :: permeg=1.0e-6
!
! Return if no fluxes to be calculated
!
if (gas_fluxes%num_bcs .le. 0) then
return
endif
!
! check some things
!
if (.not. associated(gas_fluxes%bc)) then !{
if (gas_fluxes%num_bcs .ne. 0) then !{
call mpp_error(FATAL, trim(error_header) // ' Number of gas fluxes not zero')
else !}{
return
endif !}
endif !}
!
! =====================================================================
! begin executable code
! =====================================================================
!
do n = 1, gas_fluxes%num_bcs !{
!
! only do calculations if the flux has not been overridden
!
if ( .not. gas_fluxes%bc(n)%field(ind_flux)%override) then !{
if (gas_fluxes%bc(n)%flux_type .eq. 'air_sea_gas_flux_generic') then !{
length = size(gas_fluxes%bc(n)%field(1)%values(:))
if (.not. allocated(kw)) then
allocate( kw(length) )
allocate ( cair(length) )
elseif (size(kw(:)) .ne. length) then
call mpp_error(FATAL, trim(error_header) // ' Lengths of flux fields do not match')
endif
if (gas_fluxes%bc(n)%implementation .eq. 'ocmip2') then !}{
do i = 1, length !{
if (seawater(i) == 1) then !{
gas_fluxes%bc(n)%field(ind_kw)%values(i) = gas_fluxes%bc(n)%param(1) * gas_fields_atm%bc(n)%field(ind_u10)%values(i)**2
cair(i) = &
gas_fields_ice%bc(n)%field(ind_alpha)%values(i) * &
gas_fields_atm%bc(n)%field(ind_pCair)%values(i) * &
gas_fields_atm%bc(n)%field(ind_psurf)%values(i) * gas_fluxes%bc(n)%param(2)
gas_fluxes%bc(n)%field(ind_flux)%values(i) = gas_fluxes%bc(n)%field(ind_kw)%values(i) * &
sqrt(660 / (gas_fields_ice%bc(n)%field(ind_sc_no)%values(i) + epsln)) * &
(gas_fields_ice%bc(n)%field(ind_csurf)%values(i) - cair(i))
gas_fluxes%bc(n)%field(ind_deltap)%values(i) = (gas_fields_ice%bc(n)%field(ind_csurf)%values(i) - cair(i)) / &
(gas_fields_ice%bc(n)%field(ind_alpha)%values(i) * permeg + epsln)
else !}{
gas_fluxes%bc(n)%field(ind_kw)%values(i) = 0.0
gas_fluxes%bc(n)%field(ind_flux)%values(i) = 0.0
gas_fluxes%bc(n)%field(ind_deltap)%values(i) = 0.0
cair(i) = 0.0
endif !}
enddo !} i
else !}{
call mpp_error(FATAL, ' Unknown implementation (' // trim(gas_fluxes%bc(n)%implementation) // &
') for ' // trim(gas_fluxes%bc(n)%name))
endif !}
elseif (gas_fluxes%bc(n)%flux_type .eq. 'air_sea_gas_flux') then !{
length = size(gas_fluxes%bc(n)%field(1)%values(:))
if (.not. allocated(kw)) then
allocate( kw(length) )
allocate ( cair(length) )
elseif (size(kw(:)) .ne. length) then
call mpp_error(FATAL, trim(error_header) // ' Lengths of flux fields do not match')
endif
if (gas_fluxes%bc(n)%implementation .eq. 'ocmip2_data') then !{
do i = 1, length !{
if (seawater(i) == 1) then !{
kw(i) = gas_fluxes%bc(n)%param(1) * gas_fields_atm%bc(n)%field(ind_u10)%values(i)
cair(i) = &
gas_fields_ice%bc(n)%field(ind_alpha)%values(i) * &
gas_fields_atm%bc(n)%field(ind_pCair)%values(i) * &
gas_fields_atm%bc(n)%field(ind_psurf)%values(i) * gas_fluxes%bc(n)%param(2)
gas_fluxes%bc(n)%field(ind_flux)%values(i) = kw(i) * &
(gas_fields_ice%bc(n)%field(ind_csurf)%values(i) - cair(i))
else !}{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = 0.0
cair(i) = 0.0
kw(i) = 0.0
endif !}
enddo !} i
elseif (gas_fluxes%bc(n)%implementation .eq. 'ocmip2') then !}{
do i = 1, length !{
if (seawater(i) == 1) then !{
kw(i) = gas_fluxes%bc(n)%param(1) * gas_fields_atm%bc(n)%field(ind_u10)%values(i)**2
cair(i) = &
gas_fields_ice%bc(n)%field(ind_alpha)%values(i) * &
gas_fields_atm%bc(n)%field(ind_pCair)%values(i) * &
gas_fields_atm%bc(n)%field(ind_psurf)%values(i) * gas_fluxes%bc(n)%param(2)
gas_fluxes%bc(n)%field(ind_flux)%values(i) = kw(i) * &
(gas_fields_ice%bc(n)%field(ind_csurf)%values(i) - cair(i))
else !}{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = 0.0
cair(i) = 0.0
kw(i) = 0.0
endif !}
enddo !} i
elseif (gas_fluxes%bc(n)%implementation .eq. 'linear') then !}{
do i = 1, length !{
if (seawater(i) == 1) then !{
kw(i) = gas_fluxes%bc(n)%param(1) * max(0.0, gas_fields_atm%bc(n)%field(ind_u10)%values(i) - gas_fluxes%bc(n)%param(2))
cair(i) = &
gas_fields_ice%bc(n)%field(ind_alpha)%values(i) * &
gas_fields_atm%bc(n)%field(ind_pCair)%values(i) * &
gas_fields_atm%bc(n)%field(ind_psurf)%values(i) * gas_fluxes%bc(n)%param(3)
gas_fluxes%bc(n)%field(ind_flux)%values(i) = kw(i) * &
(gas_fields_ice%bc(n)%field(ind_csurf)%values(i) - cair(i))
else !}{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = 0.0
cair(i) = 0.0
kw(i) = 0.0
endif !}
enddo !} i
else !}{
call mpp_error(FATAL, ' Unknown implementation (' // trim(gas_fluxes%bc(n)%implementation) // &
') for ' // trim(gas_fluxes%bc(n)%name))
endif !}
elseif (gas_fluxes%bc(n)%flux_type .eq. 'air_sea_deposition') then !}{
if (gas_fluxes%bc(n)%param(1) .le. 0.0) then
write (error_string, '(1pe10.3)') gas_fluxes%bc(n)%param(1)
call mpp_error(FATAL, ' Bad parameter (' // trim(error_string) // &
') for air_sea_deposition for ' // trim(gas_fluxes%bc(n)%name))
endif
length = size(gas_fluxes%bc(n)%field(1)%values(:))
if (gas_fluxes%bc(n)%implementation .eq. 'dry') then !{
do i = 1, length !{
if (seawater(i) == 1) then !{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = &
gas_fields_atm%bc(n)%field(ind_deposition)%values(i) / gas_fluxes%bc(n)%param(1)
else !}{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = 0.0
endif !}
enddo !} i
elseif (gas_fluxes%bc(n)%implementation .eq. 'wet') then !}{
do i = 1, length !{
if (seawater(i) == 1) then !{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = &
gas_fields_atm%bc(n)%field(ind_deposition)%values(i) / gas_fluxes%bc(n)%param(1)
else !}{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = 0.0
endif !}
enddo !} i
else !}{
call mpp_error(FATAL, ' Unknown implementation (' // trim(gas_fluxes%bc(n)%implementation) // &
') for ' // trim(gas_fluxes%bc(n)%name))
endif !}
elseif (gas_fluxes%bc(n)%flux_type .eq. 'land_sea_runoff') then !}{
if (gas_fluxes%bc(n)%param(1) .le. 0.0) then
write (error_string, '(1pe10.3)') gas_fluxes%bc(n)%param(1)
call mpp_error(FATAL, ' Bad parameter (' // trim(error_string) // &
') for land_sea_runoff for ' // trim(gas_fluxes%bc(n)%name))
endif
length = size(gas_fluxes%bc(n)%field(1)%values(:))
if (gas_fluxes%bc(n)%implementation .eq. 'river') then !{
do i = 1, length !{
if (seawater(i) == 1) then !{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = &
gas_fields_atm%bc(n)%field(ind_deposition)%values(i) / gas_fluxes%bc(n)%param(1)
else !}{
gas_fluxes%bc(n)%field(ind_flux)%values(i) = 0.0
endif !}
enddo !} i
else !}{
call mpp_error(FATAL, ' Unknown implementation (' // trim(gas_fluxes%bc(n)%implementation) // &
') for ' // trim(gas_fluxes%bc(n)%name))
endif !}
else !}{
call mpp_error(FATAL, ' Unknown flux_type (' // trim(gas_fluxes%bc(n)%flux_type) // &
') for ' // trim(gas_fluxes%bc(n)%name))
endif !}
endif !}
enddo !} n
if (allocated(kw)) then
deallocate(kw)
deallocate(cair)
endif
return
end subroutine atmos_ocean_fluxes_calc !}
! NAME="atmos_ocean_fluxes_calc"
end module atmos_ocean_fluxes_mod !}