Revision f501defa2ae7c687d08d78b1f0f1595d8b54b08c authored by Michael Kelleher on 27 October 2023, 21:10:59 UTC, committed by Michael Kelleher on 27 October 2023, 21:10:59 UTC
1 parent b2ea1c3
shr_fire_emis_mod.F90
module shr_fire_emis_mod
!================================================================================
! Coordinates carbon emissions fluxes from CLM fires for use as sources of
! chemical constituents in CAM
!
! This module reads fire_emis_nl namelist which specifies the compound fluxes
! that are to be passed through the model coupler.
!================================================================================
use ESMF , only : ESMF_VMGetCurrent, ESMF_VM, ESMF_VMGet
use ESMF , only : ESMF_LogFoundError, ESMF_LOGERR_PASSTHRU, ESMF_SUCCESS
use shr_kind_mod , only : r8 => shr_kind_r8, cl=>shr_kind_cl, cx=>shr_kind_cx, cs=>shr_kind_cs
use shr_sys_mod , only : shr_sys_abort
use shr_log_mod , only : logunit => shr_log_Unit
use shr_mpi_mod , only : shr_mpi_bcast
use shr_nl_mod , only : shr_nl_find_group_name
use shr_expr_parser_mod , only : shr_exp_parse, shr_exp_item_t, shr_exp_list_destroy
implicit none
private
public :: shr_fire_emis_readnl ! reads fire_emis_nl namelist
public :: shr_fire_emis_mechcomps ! points to an array of chemical compounds (in CAM-Chem mechanism) than have fire emissions
public :: shr_fire_emis_mechcomps_n ! number of unique compounds in the CAM chemical mechanism that have fire emissions
public :: shr_fire_emis_comps_n ! number of unique emissions components
public :: shr_fire_emis_linkedlist ! points to linked list of shr_fire_emis_comp_t objects
public :: shr_fire_emis_elevated ! elevated emissions in ATM
public :: shr_fire_emis_comp_ptr ! user defined type that points to fire emis data obj (shr_fire_emis_comp_t)
public :: shr_fire_emis_comp_t ! emission component data type
public :: shr_fire_emis_mechcomp_t ! data type for chemical compound in CAM mechanism than has fire emissions
logical :: fire_emis_initialized = .false. ! true => shr_fire_emis_readnl alreay called
logical :: shr_fire_emis_elevated = .true.
character(len=CL), public :: shr_fire_emis_factors_file = '' ! a table of basic fire emissions compounds
character(len=CS), public :: shr_fire_emis_ztop_token = 'Sl_fztop' ! token for emissions top of vertical distribution
integer, parameter :: name_len=16
! fire emissions component data structure (or user defined type)
type shr_fire_emis_comp_t
character(len=name_len) :: name ! emissions component name (in fire emissions input table)
integer :: index
real(r8), pointer :: emis_factors(:) ! function of plant-function-type (PFT)
real(r8) :: coeff ! emissions component coeffecient
real(r8) :: molec_weight ! molecular weight of the fire emissions compound (g/mole)
type(shr_fire_emis_comp_t), pointer :: next_emiscomp ! points to next member in the linked list
endtype shr_fire_emis_comp_t
type shr_fire_emis_comp_ptr
type(shr_fire_emis_comp_t), pointer :: ptr ! points to fire emis data obj (shr_fire_emis_comp_t)
endtype shr_fire_emis_comp_ptr
! chemical compound in CAM mechanism that has fire emissions
type shr_fire_emis_mechcomp_t
character(len=16) :: name ! compound name
type(shr_fire_emis_comp_ptr), pointer :: emis_comps(:) ! an array of pointers to fire emis components
integer :: n_emis_comps ! number of fire emis compounds that make up the emissions for this mechanis compound
end type shr_fire_emis_mechcomp_t
type(shr_fire_emis_mechcomp_t), pointer :: shr_fire_emis_mechcomps(:) ! array of chemical compounds (in CAM mechanism) that have fire emissions
type(shr_fire_emis_comp_t), pointer :: shr_fire_emis_linkedlist ! points to linked list top
integer :: shr_fire_emis_comps_n = 0 ! number of unique fire components
integer :: shr_fire_emis_mechcomps_n = 0 ! number of unique compounds in the CAM chemical mechanism that have fire emissions
!-------------------------------------------------------------------------
contains
!-------------------------------------------------------------------------
subroutine shr_fire_emis_readnl( NLFileName, emis_nflds )
!-------------------------------------------------------------------------
!
! This reads the fire_emis_nl namelist group in drv_flds_in and parses the
! namelist information for the driver, CLM, and CAM.
!
! Namelist variables:
! fire_emis_specifier, fire_emis_factors_file, fire_emis_elevated
!
! fire_emis_specifier (array of strings) -- Each array element specifies
! how CAM-Chem constituents are mapped to basic smoke compounds in
! the fire emissions factors table (fire_emis_factors_file). Each
! chemistry constituent name (left of '=' sign) is mapped to one or more
! smoke compound (separated by + sign if more than one), which can be
! proceeded by a multiplication factor (separated by '*').
! Example:
! fire_emis_specifier = 'bc_a1 = BC','pom_a1 = 1.4*OC','SO2 = SO2'
!
! fire_emis_factors_file (string) -- Input file that contains the table
! of basic compounds that make up the smoke from the CLM fires. This is
! used in CLM module FireEmisFactorsMod.
!
! fire_emis_elevated (locical) -- If true then CAM-Chem treats the fire
! emission sources as 3-D vertically distributed forcings for the
! corresponding chemical tracers.
!
!-------------------------------------------------------------------------
! input/output variables
character(len=*), intent(in) :: NLFileName ! name of namelist file
integer , intent(out) :: emis_nflds
! local variables
type(ESMF_VM) :: vm
integer :: localPet
integer :: mpicom
integer :: rc
integer :: unitn ! namelist unit number
integer :: ierr ! error code
logical :: exists ! if file exists or not
integer, parameter :: maxspc = 100
character(len=2*CX) :: fire_emis_specifier(maxspc) = ' '
character(len=CL) :: fire_emis_factors_file = ' '
logical :: fire_emis_elevated = .true.
integer :: i, tmp(1)
character(*),parameter :: F00 = "('(shr_fire_emis_readnl) ',2a)"
character(len=*), parameter :: subname='(shr_fire_emis_readnl)'
!------------------------------------------------------------------
namelist /fire_emis_nl/ fire_emis_specifier, fire_emis_factors_file, fire_emis_elevated
rc = ESMF_SUCCESS
! If other processes have already initialized megan - then the info will just be re-initialized
call ESMF_VMGetCurrent(vm, rc=rc)
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
call ESMF_VMGet(vm, localPet=localPet, mpiCommunicator=mpicom, rc=rc)
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
! Note the following still needs to be called on all processors since the mpi_bcast is a collective
! call on all the pes of mpicom
if (localPet==0) then
inquire( file=trim(NLFileName), exist=exists)
if ( exists ) then
open(newunit=unitn, file=trim(NLFilename), status='old' )
write(logunit,F00) 'Read in fire_emis_readnl namelist from: ', trim(NLFilename)
call shr_nl_find_group_name(unitn, 'fire_emis_nl', status=ierr)
! If ierr /= 0, no namelist present.
if (ierr == 0) then
read(unitn, fire_emis_nl, iostat=ierr)
if (ierr > 0) then
call shr_sys_abort( 'problem on read of fire_emis_nl namelist in shr_fire_emis_readnl' )
endif
endif
close( unitn )
end if
end if
call shr_mpi_bcast(fire_emis_specifier , mpicom)
call shr_mpi_bcast(fire_emis_factors_file , mpicom)
call shr_mpi_bcast(fire_emis_elevated , mpicom)
shr_fire_emis_factors_file = fire_emis_factors_file
shr_fire_emis_elevated = fire_emis_elevated
! parse the namelist info and initialize the module data - only if it has not been initialized
if (.not. fire_emis_initialized) then
call shr_fire_emis_init( fire_emis_specifier )
end if
emis_nflds = shr_fire_emis_mechcomps_n
end subroutine shr_fire_emis_readnl
!-------------------------------------------------------------------------
! private methods...
!-------------------------------------------------------------------------
subroutine shr_fire_emis_init( specifier )
!--------------------------------------------------
! module data initializer
!--------------------------------------------------
! input/output variables
character(len=*), intent(in) :: specifier(:)
! local variables
integer :: n_entries
integer :: i, j, k
type(shr_exp_item_t), pointer :: items_list, item
!------------------------------------------------------
nullify(shr_fire_emis_linkedlist)
items_list => shr_exp_parse( specifier, nitems=n_entries )
allocate(shr_fire_emis_mechcomps(n_entries))
shr_fire_emis_mechcomps(:)%n_emis_comps = 0
item => items_list
i = 1
do while(associated(item))
do k=1,shr_fire_emis_mechcomps_n
if ( trim(shr_fire_emis_mechcomps(k)%name) == trim(item%name) ) then
call shr_sys_abort( 'shr_fire_emis_init : multiple emissions definitions specified for : '//trim(item%name))
endif
enddo
if (len_trim(item%name) .le. name_len) then
shr_fire_emis_mechcomps(i)%name = item%name(1:name_len)
else
call shr_sys_abort("shr_file_emis_init : name too long for data structure :"//trim(item%name))
endif
shr_fire_emis_mechcomps(i)%n_emis_comps = item%n_terms
allocate(shr_fire_emis_mechcomps(i)%emis_comps(item%n_terms))
do j = 1,item%n_terms
shr_fire_emis_mechcomps(i)%emis_comps(j)%ptr => add_emis_comp( item%vars(j), item%coeffs(j) )
enddo
shr_fire_emis_mechcomps_n = shr_fire_emis_mechcomps_n+1
item => item%next_item
i = i+1
enddo
if (associated(items_list)) call shr_exp_list_destroy(items_list)
! Need to explicitly add Fl_ based on naming convention
fire_emis_initialized = .true.
end subroutine shr_fire_emis_init
!-------------------------------------------------------------------------
function add_emis_comp( name, coeff ) result(emis_comp)
character(len=*), intent(in) :: name
real(r8), intent(in) :: coeff
type(shr_fire_emis_comp_t), pointer :: emis_comp
emis_comp => get_emis_comp_by_name(shr_fire_emis_linkedlist, name)
if(associated(emis_comp)) then
! already in the list so return...
return
endif
! create new emissions component and add it to the list
allocate(emis_comp)
! element%index = lookup_element( name )
! element%emis_factors = get_factors( list_elem%index )
emis_comp%index = shr_fire_emis_comps_n+1
emis_comp%name = trim(name)
emis_comp%coeff = coeff
nullify(emis_comp%next_emiscomp)
call add_emis_comp_to_list(emis_comp)
end function add_emis_comp
!-------------------------------------------------------------------------
recursive function get_emis_comp_by_name(list_comp, name) result(emis_comp)
type(shr_fire_emis_comp_t), pointer :: list_comp
character(len=*), intent(in) :: name ! variable name
type(shr_fire_emis_comp_t), pointer :: emis_comp ! returned object
if(associated(list_comp)) then
if(list_comp%name .eq. name) then
emis_comp => list_comp
else
emis_comp => get_emis_comp_by_name(list_comp%next_emiscomp, name)
end if
else
nullify(emis_comp)
end if
end function get_emis_comp_by_name
!-------------------------------------------------------------------------
subroutine add_emis_comp_to_list( new_emis_comp )
type(shr_fire_emis_comp_t), target, intent(in) :: new_emis_comp
type(shr_fire_emis_comp_t), pointer :: list_comp
if(associated(shr_fire_emis_linkedlist)) then
list_comp => shr_fire_emis_linkedlist
do while(associated(list_comp%next_emiscomp))
list_comp => list_comp%next_emiscomp
end do
list_comp%next_emiscomp => new_emis_comp
else
shr_fire_emis_linkedlist => new_emis_comp
end if
shr_fire_emis_comps_n = shr_fire_emis_comps_n + 1
end subroutine add_emis_comp_to_list
endmodule shr_fire_emis_mod
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...