Skip to content

Commit 1f06c58

Browse files
authored
Merge pull request #339 from fvitt/megan_expr
Updates to the MEGAN specifier string parser
2 parents c6f23c3 + 690cf28 commit 1f06c58

2 files changed

Lines changed: 113 additions & 90 deletions

File tree

Lines changed: 92 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
!=============================================================================
22
! expression parser utility --
33
! for parsing simple linear mathematical expressions of the form
4-
! X = a*Y + b*Z + ...
4+
! X = a*R + b*S + c*(X + Y + Z) ...
55
!
66
!=============================================================================
77
module shr_expr_parser_mod
88
use shr_kind_mod,only : r8 => shr_kind_r8
9-
use shr_kind_mod,only : cx => shr_kind_cx
9+
use shr_kind_mod,only : CXX => shr_kind_cxx
1010

1111
implicit none
1212
private
@@ -35,82 +35,122 @@ function shr_exp_parse( exp_array, nitems ) result(exp_items_list)
3535
integer, optional, intent(out) :: nitems ! number of expressions parsed
3636
type(shr_exp_item_t), pointer :: exp_items_list ! linked list of items returned
3737

38-
integer :: i,j, jj, nmax, nterms, n_exp_items
39-
character(len=cx) :: tmp_str
38+
integer :: i,j, n_exp_items
4039
type(shr_exp_item_t), pointer :: exp_item, list_item
40+
integer :: ndxs(512)
41+
integer :: nelem, j1,j2,k
42+
character(len=CXX) :: tmp_str, tmp_name
43+
character(len=8) :: xchr ! multipler
44+
real(r8) :: xdbl
45+
real(r8) :: coeff0
46+
logical :: more_to_come
47+
character(len=CXX), allocatable :: sums_grps(:)
48+
character(len=CXX) :: sum_string
49+
50+
allocate(sums_grps(size(exp_array)))
4151

4252
nullify( exp_items_list )
4353
nullify( exp_item )
4454
nullify( list_item )
4555

46-
n_exp_items = 0
47-
nmax = size( exp_array )
56+
sums_grps(:) = ' '
4857

49-
do i = 1,nmax
50-
if (len_trim(exp_array(i))>0) then
58+
! combine lines that have a trailing "+" with the next line
59+
i=1
60+
j=1
61+
loop1: do while( len_trim(exp_array(i)) > 0 )
5162

52-
j = scan( exp_array(i), '=' )
63+
k = scan(exp_array(i), '+', back=.true. )
64+
more_to_come = k == len_trim(exp_array(i)) ! line ends with "+"
5365

54-
if ( j>0 ) then
66+
if ( more_to_come ) then
67+
sums_grps(j) = trim(sums_grps(j)) // trim(adjustl(exp_array(i)))
68+
else
69+
sums_grps(j) = trim(sums_grps(j)) // trim(adjustl(exp_array(i)))
70+
j = j+1
71+
endif
72+
73+
i = i+1
74+
if ( i > size(exp_array) ) exit loop1
5575

56-
n_exp_items = n_exp_items + 1
76+
end do loop1
5777

58-
allocate( exp_item )
59-
exp_item%n_terms = 0
60-
exp_item%name = trim(adjustl(exp_array(i)(:j-1)))
78+
n_exp_items = j-1
6179

62-
tmp_str = trim(adjustl(exp_array(i)(j+1:)))
80+
! a group is a summation of terms
6381

64-
nterms = 1
65-
jj = scan( tmp_str, '+' )
66-
do while(jj>0)
67-
nterms = nterms + 1
68-
tmp_str = tmp_str(jj+1:)
69-
jj = scan( tmp_str, '+' )
70-
enddo
82+
! parse the individual sum strings... and form the groupings
83+
has_grps: if (n_exp_items>0) then
7184

72-
allocate( exp_item%vars(nterms) )
73-
allocate( exp_item%coeffs(nterms) )
85+
! from shr_megan_mod ... should be generalized and shared...
86+
grploop: do i = 1,n_exp_items
7487

75-
tmp_str = trim(adjustl(exp_array(i)(j+1:)))
88+
! parse out the term names
89+
! from first parsing out the terms in the summation equation ("+" separates the terms)
7690

91+
sum_string = sums_grps(i)
92+
j = scan( sum_string, '=' )
93+
nelem = 1
94+
ndxs(nelem) = j ! ndxs stores the index of each term of the equation
95+
96+
! find indices of all the terms in the equation
97+
tmp_str = trim( sum_string(j+1:) )
98+
j = scan( tmp_str, '+' )
99+
do while(j>0)
100+
nelem = nelem+1
101+
ndxs(nelem) = ndxs(nelem-1) + j
102+
tmp_str = tmp_str(j+1:)
77103
j = scan( tmp_str, '+' )
104+
enddo
105+
ndxs(nelem+1) = len(sum_string)+1
78106

79-
if (j>0) then
80-
call set_coefvar( tmp_str(:j-1), exp_item )
81-
tmp_str = tmp_str(j-1:)
82-
else
83-
call set_coefvar( tmp_str, exp_item )
84-
endif
107+
allocate( exp_item )
85108

86-
else
109+
exp_item%n_terms = nelem ! number of terms
87110

88-
tmp_str = trim(adjustl(exp_array(i))) ! assumed to begin with '+'
111+
exp_item%name = trim(adjustl( sum_string(:ndxs(1)-1))) ! thing to the left of the "=" is used as the name of the group
89112

90-
endif
113+
! now that we have the number of terms in the summation allocate memory for the terms
114+
allocate( exp_item%vars(nelem) )
115+
allocate( exp_item%coeffs(nelem) )
91116

92-
! at this point tmp_str begins with '+'
93-
j = scan( tmp_str, '+' )
117+
coeff0 = 1._r8 ! default multiplier
94118

95-
if (j>0) then
119+
! now parse out the multiplier from the terms
120+
elmloop: do k = 1,nelem
96121

97-
! remove the leading + ...
98-
tmp_str = tmp_str(j+1:)
99-
j = scan( tmp_str, '+' )
122+
exp_item%coeffs(k) = coeff0
100123

101-
do while(j>0)
124+
! get the term name which follows the '*' operator if the is one
125+
tmp_name = adjustl(sum_string(ndxs(k)+1:ndxs(k+1)-1))
102126

103-
call set_coefvar( tmp_str(:j-1), exp_item )
127+
j = scan( tmp_name, '*' )
128+
if (j>0) then
104129

105-
tmp_str = tmp_str(j+1:)
106-
j = scan( tmp_str, '+' )
130+
xchr = tmp_name(1:j-1) ! get the multipler (left of the '*')
131+
read( xchr, * ) xdbl ! convert the string to a real
132+
exp_item%coeffs(k) = xdbl ! store the multiplier
107133

108-
enddo
134+
j1 = scan( tmp_name, '(' )
135+
if (j1>0) then
136+
coeff0 = xdbl
137+
tmp_name = trim(adjustl(tmp_name(j1+1:))) ! get the term name (right of the '*')
138+
else
139+
coeff0 = 1._r8
140+
tmp_name = trim(adjustl(tmp_name(j+1:))) ! get the term name (right of the '*')
141+
endif
109142

110-
call set_coefvar( tmp_str, exp_item )
143+
endif
111144

112-
endif
145+
j2 = scan( tmp_name, ')' )
146+
if (j2>0) then
147+
coeff0 = 1._r8
148+
tmp_name = tmp_name(1:j2-1)
149+
endif
113150

151+
exp_item%vars(k) = trim(tmp_name)
152+
153+
enddo elmloop
114154

115155
if (associated(exp_item)) then
116156
if (associated(exp_items_list)) then
@@ -124,13 +164,16 @@ function shr_exp_parse( exp_array, nitems ) result(exp_items_list)
124164
endif
125165
endif
126166

127-
endif
128-
enddo
167+
168+
enddo grploop
169+
endif has_grps
129170

130171
if ( present(nitems) ) then
131172
nitems = n_exp_items
132173
endif
133174

175+
deallocate(sums_grps)
176+
134177
end function shr_exp_parse
135178

136179
! -----------------------------------------------------------------
@@ -157,29 +200,4 @@ subroutine shr_exp_list_destroy( list )
157200

158201
end subroutine shr_exp_list_destroy
159202

160-
!==========================
161-
! Private Methods
162-
163-
! -----------------------------------------------------------------
164-
! -----------------------------------------------------------------
165-
subroutine set_coefvar( term, item )
166-
character(len=*), intent(in) :: term
167-
type(shr_exp_item_t) , intent(inout) :: item
168-
169-
integer :: k, n
170-
171-
item%n_terms = item%n_terms + 1
172-
n = item%n_terms
173-
174-
k = scan( term, '*' )
175-
if (k>0) then
176-
item%vars(n) = trim(adjustl(term(k+1:)))
177-
read( term(:k-1), *) item%coeffs(n)
178-
else
179-
item%vars(n) = trim(adjustl(term))
180-
item%coeffs(n) = 1.0_r8
181-
endif
182-
183-
end subroutine set_coefvar
184-
185203
end module shr_expr_parser_mod

cesm/nuopc_cap_share/shr_megan_mod.F90

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@ module shr_megan_mod
55
! MEGAN = Model of Emissions of Gases and Aerosols from Nature
66
!
77
! This reads the megan_emis_nl namelist in drv_flds_in and makes the relavent
8-
! information available to CAM, CLM, and driver.
9-
! - The driver sets up CLM to CAM communication for the VOC flux fields.
10-
! - CLM needs to know what specific VOC fluxes need to be passed to the coupler
8+
! information available to CAM, CLM, and driver.
9+
! - The driver sets up CLM to CAM communication for the VOC flux fields.
10+
! - CLM needs to know what specific VOC fluxes need to be passed to the coupler
1111
! and how to assemble the fluxes.
1212
! - CAM needs to know what specific VOC fluxes to expect from CLM.
1313
!================================================================================
1414

1515
use ESMF , only : ESMF_VMGetCurrent, ESMF_VM, ESMF_VMGet
16-
use ESMF , only : ESMF_LogFoundError, ESMF_LOGERR_PASSTHRU, ESMF_SUCCESS
17-
use shr_kind_mod , only : r8 => shr_kind_r8, cl=>shr_kind_cl, cx=>shr_kind_cx, cs=>shr_kind_cs
16+
use ESMF , only : ESMF_LogFoundError, ESMF_LOGERR_PASSTHRU
17+
use shr_kind_mod , only : r8 => shr_kind_r8, cl=>shr_kind_cl, cx=>shr_kind_cx
1818
use shr_sys_mod , only : shr_sys_abort
1919
use shr_log_mod , only : shr_log_getLogUnit
2020
use shr_mpi_mod , only : shr_mpi_bcast
2121
use shr_nl_mod , only : shr_nl_find_group_name
2222
use shr_expr_parser_mod , only : shr_exp_parse, shr_exp_item_t, shr_exp_list_destroy
23-
23+
2424
implicit none
2525
private
2626

@@ -68,6 +68,9 @@ module shr_megan_mod
6868
! switch to use mapped emission factors
6969
logical :: shr_megan_mapped_emisfctrs = .false.
7070

71+
integer :: localPet = -huge(1)
72+
integer :: logunit = -huge(1)
73+
7174
!--------------------------------------------------------
7275
contains
7376
!--------------------------------------------------------
@@ -100,7 +103,8 @@ subroutine shr_megan_readnl( NLFileName, megan_nflds)
100103
! Example:
101104
! &megan_emis_nl
102105
! megan_specifier = 'ISOP = isoprene',
103-
! 'C10H16 = myrcene + sabinene + limonene + carene_3 + ocimene_t_b + pinene_b + ...',
106+
! 'C10H16 = myrcene + sabinene + limonene + carene_3 + ocimene_t_b + pinene_b + ',
107+
! ' thujene_a + bornene + 0.5*(terpineol_4 + terpineol_a + terpinyl_ACT_a + myrtenal) + ...',
104108
! 'CH3OH = methanol',
105109
! 'C2H5OH = ethanol',
106110
! 'CH2O = formaldehyde',
@@ -109,25 +113,22 @@ subroutine shr_megan_readnl( NLFileName, megan_nflds)
109113
! megan_factors_file = '$datapath/megan_emis_factors.nc'
110114
! /
111115
!-------------------------------------------------------------------------
112-
116+
113117
! input/output variables
114118
character(len=*), intent(in) :: NLFileName
115119
integer, intent(out) :: megan_nflds
116120

117121
! local variables
118122
type(ESMF_VM) :: vm
119-
integer :: localPet
120123
integer :: mpicom
121124
integer :: unitn ! namelist unit number
122125
integer :: ierr ! error code
123126
logical :: exists ! if file exists or not
124-
integer, parameter :: maxspc = 100
125-
character(len=2*CX) :: megan_specifier(maxspc) = ' '
127+
integer, parameter :: maxspc = 200
128+
character(len=CX) :: megan_specifier(maxspc) = ' '
126129
logical :: megan_mapped_emisfctrs = .false.
127130
character(len=CL) :: megan_factors_file = ' '
128131
integer :: rc
129-
integer :: logunit
130-
integer :: i, tmp(1)
131132
character(*), parameter :: F00 = "('(shr_megan_readnl) ',2a)"
132133
character(len=*), parameter :: subname='(shr_megan_readnl)'
133134
!--------------------------------------------------------------
@@ -140,12 +141,12 @@ subroutine shr_megan_readnl( NLFileName, megan_nflds)
140141
end if
141142

142143
call ESMF_VMGetCurrent(vm, rc=rc)
143-
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
144+
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
144145

145146
call ESMF_VMGet(vm, localPet=localPet, mpiCommunicator=mpicom, rc=rc)
146-
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
147+
if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return
147148
call shr_log_getLogUnit(logunit)
148-
! Note the following still needs to be called on all processors since the mpi_bcast is a collective
149+
! Note the following still needs to be called on all processors since the mpi_bcast is a collective
149150
! call on all the pes of mpicom
150151
if (localPet==0) then
151152
inquire( file=trim(NLFileName), exist=exists)
@@ -204,6 +205,8 @@ subroutine shr_megan_init( specifier)
204205
allocate(shr_megan_mechcomps(n_entries))
205206
shr_megan_mechcomps(:)%n_megan_comps = 0
206207

208+
if (localPet==0) write(logunit,*) 'MEGAN entries:'
209+
207210
item => items_list
208211
i = 1
209212
do while(associated(item))
@@ -221,7 +224,9 @@ subroutine shr_megan_init( specifier)
221224
shr_megan_mechcomps(i)%n_megan_comps = item%n_terms
222225
allocate(shr_megan_mechcomps(i)%megan_comps(item%n_terms))
223226

227+
if (localPet==0) write(logunit,*) ' species : ', item%name
224228
do j = 1,item%n_terms
229+
if (localPet==0) write(logunit,'(f12.4,a,a)') item%coeffs(j),' * ', item%vars(j)
225230
shr_megan_mechcomps(i)%megan_comps(j)%ptr => add_megan_comp( item%vars(j), item%coeffs(j) )
226231
enddo
227232
shr_megan_mechcomps_n = shr_megan_mechcomps_n+1

0 commit comments

Comments
 (0)