Line data Source code
1 : module rad_constituents
2 :
3 : !------------------------------------------------------------------------------------------------
4 : !
5 : ! Provide constituent distributions and properties to the radiation and
6 : ! cloud microphysics routines.
7 : !
8 : ! The logic to control which constituents are used in the climate calculations
9 : ! and which are used in diagnostic radiation calculations is contained in this module.
10 : !
11 : !------------------------------------------------------------------------------------------------
12 :
13 : use shr_kind_mod, only: r8 => shr_kind_r8
14 : use spmd_utils, only: masterproc
15 : use ppgrid, only: pcols, pver
16 : use physconst, only: rga
17 : use physics_types, only: physics_state
18 : use phys_control, only: use_simple_phys
19 : use constituents, only: cnst_get_ind
20 : use radconstants, only: nradgas, rad_gas_index
21 : use phys_prop, only: physprop_accum_unique_files, physprop_init, &
22 : physprop_get_id, ot_length
23 : use cam_history, only: addfld, fieldname_len, outfld, horiz_only
24 : use physics_buffer, only: physics_buffer_desc, pbuf_get_field, pbuf_get_index
25 :
26 :
27 : use cam_abortutils, only: endrun
28 : use cam_logfile, only: iulog
29 :
30 : implicit none
31 : private
32 : save
33 :
34 : ! Public interfaces
35 :
36 : public :: &
37 : rad_cnst_readnl, &! read namelist values and parse
38 : rad_cnst_init, &! find optics files and all constituents
39 : rad_cnst_get_info, &! return info about climate/diagnostic lists
40 : rad_cnst_get_mode_idx, &! return mode index of specified mode type
41 : rad_cnst_get_spec_idx, &! return specie index of specified specie type
42 : rad_cnst_get_gas, &! return pointer to mmr for gasses
43 : rad_cnst_get_aer_mmr, &! return pointer to mmr for aerosols
44 : rad_cnst_get_mam_mmr_idx, &! get constituent index of mam specie mmr (climate list only)
45 : rad_cnst_get_aer_props, &! return physical properties for aerosols
46 : rad_cnst_get_mode_props, &! return physical properties for aerosol modes
47 : rad_cnst_get_mode_num, &! return mode number mixing ratio
48 : rad_cnst_get_mode_num_idx, &! get constituent index of mode number m.r. (climate list only)
49 : rad_cnst_out, &! output constituent diagnostics (mass per layer and column burden)
50 : rad_cnst_get_call_list ! return list of active climate/diagnostic calls to radiation
51 :
52 : public :: rad_cnst_num_name
53 :
54 : integer, parameter :: cs1 = 256
55 : integer, public, parameter :: N_DIAG = 10
56 : character(len=cs1), public :: iceopticsfile, liqopticsfile
57 : character(len=32), public :: icecldoptics,liqcldoptics
58 : logical, public :: oldcldoptics = .false.
59 :
60 : ! Private module data
61 :
62 : ! max number of strings in mode definitions
63 : integer, parameter :: n_mode_str = 120
64 :
65 : ! max number of externally mixed entities in the climate/diag lists
66 : integer, parameter :: n_rad_cnst = N_RAD_CNST
67 :
68 : ! Namelist variables
69 : character(len=cs1), dimension(n_mode_str) :: mode_defs = ' '
70 : character(len=cs1) :: rad_climate(n_rad_cnst) = ' '
71 : character(len=cs1) :: rad_diag_1(n_rad_cnst) = ' '
72 : character(len=cs1) :: rad_diag_2(n_rad_cnst) = ' '
73 : character(len=cs1) :: rad_diag_3(n_rad_cnst) = ' '
74 : character(len=cs1) :: rad_diag_4(n_rad_cnst) = ' '
75 : character(len=cs1) :: rad_diag_5(n_rad_cnst) = ' '
76 : character(len=cs1) :: rad_diag_6(n_rad_cnst) = ' '
77 : character(len=cs1) :: rad_diag_7(n_rad_cnst) = ' '
78 : character(len=cs1) :: rad_diag_8(n_rad_cnst) = ' '
79 : character(len=cs1) :: rad_diag_9(n_rad_cnst) = ' '
80 : character(len=cs1) :: rad_diag_10(n_rad_cnst) = ' '
81 :
82 : ! type to provide access to the components of a mode
83 : type :: mode_component_t
84 : integer :: nspec
85 : ! For "source" variables below, value is:
86 : ! 'N' if in pbuf (non-advected)
87 : ! 'A' if in state (advected)
88 : character(len= 1) :: source_num_a ! source of interstitial number conc field
89 : character(len= 32) :: camname_num_a ! name registered in pbuf or constituents for number mixing ratio of interstitial species
90 : character(len= 1) :: source_num_c ! source of cloud borne number conc field
91 : character(len= 32) :: camname_num_c ! name registered in pbuf or constituents for number mixing ratio of cloud borne species
92 : character(len= 1), pointer :: source_mmr_a(:) ! source of interstitial specie mmr fields
93 : character(len= 32), pointer :: camname_mmr_a(:) ! name registered in pbuf or constituents for mmr of interstitial components
94 : character(len= 1), pointer :: source_mmr_c(:) ! source of cloud borne specie mmr fields
95 : character(len= 32), pointer :: camname_mmr_c(:) ! name registered in pbuf or constituents for mmr of cloud borne components
96 : character(len= 32), pointer :: type(:) ! specie type (as used in MAM code)
97 : character(len=cs1), pointer :: props(:) ! file containing specie properties
98 : integer :: idx_num_a ! index in pbuf or constituents for number mixing ratio of interstitial species
99 : integer :: idx_num_c ! index in pbuf for number mixing ratio of interstitial species
100 : integer, pointer :: idx_mmr_a(:) ! index in pbuf or constituents for mmr of interstitial species
101 : integer, pointer :: idx_mmr_c(:) ! index in pbuf for mmr of interstitial species
102 : integer, pointer :: idx_props(:) ! ID used to access physical properties of mode species from phys_prop module
103 : end type mode_component_t
104 :
105 : ! type to provide access to all modes
106 : type :: modes_t
107 : integer :: nmodes
108 : character(len= 32), pointer :: names(:) ! names used to identify a mode in the climate/diag lists
109 : character(len= 32), pointer :: types(:) ! type of mode (as used in MAM code)
110 : type(mode_component_t), pointer :: comps(:) ! components which define the mode
111 : end type modes_t
112 :
113 : type(modes_t), target :: modes ! mode definitions
114 :
115 : ! type to provide access to the data parsed from the rad_climate and rad_diag_* strings
116 : type :: rad_cnst_namelist_t
117 : integer :: ncnst
118 : character(len= 1), pointer :: source(:) ! 'A' for state (advected), 'N' for pbuf (non-advected),
119 : ! 'M' for mode, 'Z' for zero
120 : character(len= 64), pointer :: camname(:) ! name registered in pbuf or constituents
121 : character(len=cs1), pointer :: radname(:) ! radname is the name as identfied in radiation,
122 : ! must be one of (rgaslist if a gas) or
123 : ! (/fullpath/filename.nc if an aerosol)
124 : character(len= 1), pointer :: type(:) ! 'A' if aerosol, 'G' if gas, 'M' if mode
125 : end type rad_cnst_namelist_t
126 :
127 : type(rad_cnst_namelist_t) :: namelist(0:N_DIAG) ! gas, bulk aerosol, and modal components used in
128 : ! climate/diagnostic calculations
129 :
130 : logical :: active_calls(0:N_DIAG) ! active_calls(i) is true if the i-th call to radiation is
131 : ! specified. Note that the 0th call is for the climate
132 : ! calculation which is always made.
133 :
134 : ! Storage for gas components in the climate/diagnostic lists
135 :
136 : type :: gas_t
137 : character(len=1) :: source ! A for state (advected), N for pbuf (non-advected), Z for zero
138 : character(len=64) :: camname ! name of constituent in physics state or buffer
139 : character(len=32) :: mass_name ! name for mass per layer field in history output
140 : integer :: idx ! index from constituents or from pbuf
141 : end type gas_t
142 :
143 : type :: gaslist_t
144 : integer :: ngas
145 : character(len=2) :: list_id ! set to " " for climate list, or two character integer
146 : ! (include leading zero) to identify diagnostic list
147 : type(gas_t), pointer :: gas(:) ! dimension(ngas) where ngas = nradgas is from radconstants
148 : end type gaslist_t
149 :
150 : type(gaslist_t), target :: gaslist(0:N_DIAG) ! gasses used in climate/diagnostic calculations
151 :
152 : ! Storage for bulk aerosol components in the climate/diagnostic lists
153 :
154 : type :: aerosol_t
155 : character(len=1) :: source ! A for state (advected), N for pbuf (non-advected), Z for zero
156 : character(len=64) :: camname ! name of constituent in physics state or buffer
157 : character(len=cs1) :: physprop_file ! physprop filename
158 : character(len=32) :: mass_name ! name for mass per layer field in history output
159 : integer :: idx ! index of constituent in physics state or buffer
160 : integer :: physprop_id ! ID used to access physical properties from phys_prop module
161 : end type aerosol_t
162 :
163 : type :: aerlist_t
164 : integer :: numaerosols ! number of aerosols
165 : character(len=2) :: list_id ! set to " " for climate list, or two character integer
166 : ! (include leading zero) to identify diagnostic list
167 : type(aerosol_t), pointer :: aer(:) ! dimension(numaerosols)
168 : end type aerlist_t
169 :
170 : type(aerlist_t), target :: aerosollist(0:N_DIAG) ! list of aerosols used in climate/diagnostic calcs
171 :
172 : ! storage for modal aerosol components in the climate/diagnostic lists
173 :
174 : type :: modelist_t
175 : integer :: nmodes ! number of modes
176 : character(len=2) :: list_id ! set to " " for climate list, or two character integer
177 : ! (include leading zero) to identify diagnostic list
178 : integer, pointer :: idx(:) ! index of the mode in the mode definition object
179 : character(len=cs1), pointer :: physprop_files(:) ! physprop filename
180 : integer, pointer :: idx_props(:) ! index of the mode properties in the physprop object
181 : end type modelist_t
182 :
183 : type(modelist_t), target :: ma_list(0:N_DIAG) ! list of aerosol modes used in climate/diagnostic calcs
184 :
185 :
186 : ! values for constituents with requested value of zero
187 : real(r8), allocatable, target :: zero_cols(:,:)
188 :
189 : ! define generic interface routines
190 : interface rad_cnst_get_info
191 : module procedure rad_cnst_get_info
192 : module procedure rad_cnst_get_info_by_mode
193 : module procedure rad_cnst_get_info_by_mode_spec
194 : module procedure rad_cnst_get_info_by_spectype
195 : end interface
196 :
197 : interface rad_cnst_get_aer_mmr
198 : module procedure rad_cnst_get_aer_mmr_by_idx
199 : module procedure rad_cnst_get_mam_mmr_by_idx
200 : end interface
201 :
202 : interface rad_cnst_get_aer_props
203 : module procedure rad_cnst_get_aer_props_by_idx
204 : module procedure rad_cnst_get_mam_props_by_idx
205 : end interface
206 :
207 : logical :: verbose = .true.
208 : character(len=1), parameter :: nl = achar(10)
209 :
210 : integer, parameter :: num_mode_types = 9
211 : integer, parameter :: num_spec_types = 8
212 : character(len=14), parameter :: mode_type_names(num_mode_types) = (/ &
213 : 'accum ', 'aitken ', 'primary_carbon', 'fine_seasalt ', &
214 : 'fine_dust ', 'coarse ', 'coarse_seasalt', 'coarse_dust ', &
215 : 'coarse_strat ' /)
216 : character(len=9), parameter :: spec_type_names(num_spec_types) = (/ &
217 : 'sulfate ', 'ammonium ', 'nitrate ', 'p-organic', &
218 : 's-organic', 'black-c ', 'seasalt ', 'dust '/)
219 :
220 :
221 : !==============================================================================
222 : contains
223 : !==============================================================================
224 :
225 1536 : subroutine rad_cnst_readnl(nlfile)
226 :
227 : ! Read rad_cnst_nl namelist group. Parse input.
228 :
229 : use namelist_utils, only: find_group_name
230 : use units, only: getunit, freeunit
231 : use mpishorthand
232 :
233 : character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
234 :
235 : ! Local variables
236 : integer :: unitn, ierr, i
237 : character(len=2) :: suffix
238 1536 : character(len=1), pointer :: ctype(:)
239 : character(len=*), parameter :: subname = 'rad_cnst_readnl'
240 :
241 : namelist /rad_cnst_nl/ mode_defs, &
242 : rad_climate, &
243 : rad_diag_1, &
244 : rad_diag_2, &
245 : rad_diag_3, &
246 : rad_diag_4, &
247 : rad_diag_5, &
248 : rad_diag_6, &
249 : rad_diag_7, &
250 : rad_diag_8, &
251 : rad_diag_9, &
252 : rad_diag_10, &
253 : iceopticsfile, &
254 : liqopticsfile, &
255 : icecldoptics, &
256 : liqcldoptics, &
257 : oldcldoptics
258 :
259 : !-----------------------------------------------------------------------------
260 :
261 0 : if (use_simple_phys) return
262 :
263 1536 : if (masterproc) then
264 2 : unitn = getunit()
265 2 : open( unitn, file=trim(nlfile), status='old' )
266 2 : call find_group_name(unitn, 'rad_cnst_nl', status=ierr)
267 2 : if (ierr == 0) then
268 2 : read(unitn, rad_cnst_nl, iostat=ierr)
269 2 : if (ierr /= 0) then
270 0 : call endrun(subname // ':: ERROR reading namelist')
271 : end if
272 : end if
273 2 : close(unitn)
274 2 : call freeunit(unitn)
275 : end if
276 :
277 : #ifdef SPMD
278 : ! Broadcast namelist variables
279 1536 : call mpibcast (mode_defs, len(mode_defs(1))*n_mode_str, mpichar, 0, mpicom)
280 1536 : call mpibcast (rad_climate, len(rad_climate(1))*n_rad_cnst, mpichar, 0, mpicom)
281 1536 : call mpibcast (rad_diag_1, len(rad_diag_1(1))*n_rad_cnst, mpichar, 0, mpicom)
282 1536 : call mpibcast (rad_diag_2, len(rad_diag_2(1))*n_rad_cnst, mpichar, 0, mpicom)
283 1536 : call mpibcast (rad_diag_3, len(rad_diag_3(1))*n_rad_cnst, mpichar, 0, mpicom)
284 1536 : call mpibcast (rad_diag_4, len(rad_diag_4(1))*n_rad_cnst, mpichar, 0, mpicom)
285 1536 : call mpibcast (rad_diag_5, len(rad_diag_5(1))*n_rad_cnst, mpichar, 0, mpicom)
286 1536 : call mpibcast (rad_diag_6, len(rad_diag_6(1))*n_rad_cnst, mpichar, 0, mpicom)
287 1536 : call mpibcast (rad_diag_7, len(rad_diag_7(1))*n_rad_cnst, mpichar, 0, mpicom)
288 1536 : call mpibcast (rad_diag_8, len(rad_diag_8(1))*n_rad_cnst, mpichar, 0, mpicom)
289 1536 : call mpibcast (rad_diag_9, len(rad_diag_9(1))*n_rad_cnst, mpichar, 0, mpicom)
290 1536 : call mpibcast (rad_diag_10, len(rad_diag_10(1))*n_rad_cnst, mpichar, 0, mpicom)
291 1536 : call mpibcast (iceopticsfile, len(iceopticsfile), mpichar, 0, mpicom)
292 1536 : call mpibcast (liqopticsfile, len(liqopticsfile), mpichar, 0, mpicom)
293 1536 : call mpibcast (liqcldoptics, len(liqcldoptics), mpichar, 0, mpicom)
294 1536 : call mpibcast (icecldoptics, len(icecldoptics), mpichar, 0, mpicom)
295 1536 : call mpibcast (oldcldoptics, 1, mpilog , 0, mpicom)
296 : #endif
297 :
298 : ! Parse the namelist input strings
299 :
300 : ! Mode definition stings
301 1536 : call parse_mode_defs(mode_defs, modes)
302 :
303 : ! Lists of externally mixed entities for climate and diagnostic calculations
304 18432 : do i = 0,N_DIAG
305 1536 : select case (i)
306 : case(0)
307 1536 : call parse_rad_specifier(rad_climate, namelist(i))
308 : case (1)
309 1536 : call parse_rad_specifier(rad_diag_1, namelist(i))
310 : case (2)
311 1536 : call parse_rad_specifier(rad_diag_2, namelist(i))
312 : case (3)
313 1536 : call parse_rad_specifier(rad_diag_3, namelist(i))
314 : case (4)
315 1536 : call parse_rad_specifier(rad_diag_4, namelist(i))
316 : case (5)
317 1536 : call parse_rad_specifier(rad_diag_5, namelist(i))
318 : case (6)
319 1536 : call parse_rad_specifier(rad_diag_6, namelist(i))
320 : case (7)
321 1536 : call parse_rad_specifier(rad_diag_7, namelist(i))
322 : case (8)
323 1536 : call parse_rad_specifier(rad_diag_8, namelist(i))
324 : case (9)
325 1536 : call parse_rad_specifier(rad_diag_9, namelist(i))
326 : case (10)
327 16896 : call parse_rad_specifier(rad_diag_10, namelist(i))
328 : end select
329 : enddo
330 :
331 : ! were there any constituents specified for the nth diagnostic call?
332 : ! if so, radiation will make a call with those consituents
333 18432 : active_calls(:) = (namelist(:)%ncnst > 0)
334 :
335 : ! Initialize the gas and aerosol lists with the information from the
336 : ! namelist. This is done here so that this information is available via
337 : ! the query functions at the time when the register methods are called.
338 :
339 : ! Set the list_id fields which distinquish the climate and diagnostic lists
340 18432 : do i = 0, N_DIAG
341 18432 : if (active_calls(i)) then
342 1536 : if (i > 0) then
343 0 : write(suffix, fmt = '(i2.2)') i
344 : else
345 1536 : suffix=' '
346 : end if
347 1536 : aerosollist(i)%list_id = suffix
348 1536 : gaslist(i)%list_id = suffix
349 1536 : ma_list(i)%list_id = suffix
350 : end if
351 : end do
352 :
353 : ! Create a list of the unique set of filenames containing property data
354 :
355 : ! Start with the bulk aerosol species in the climate/diagnostic lists.
356 : ! The physprop_accum_unique_files routine has the side effect of returning the number
357 : ! of bulk aerosols in each list (they're identified by type='A').
358 18432 : do i = 0, N_DIAG
359 18432 : if (active_calls(i)) then
360 : call physprop_accum_unique_files(namelist(i)%radname, namelist(i)%type)
361 : endif
362 : enddo
363 :
364 : ! Add physprop files for the species from the mode definitions.
365 1536 : do i = 1, modes%nmodes
366 0 : allocate(ctype(modes%comps(i)%nspec))
367 0 : ctype = 'A'
368 0 : call physprop_accum_unique_files(modes%comps(i)%props, ctype)
369 1536 : deallocate(ctype)
370 : end do
371 :
372 : ! Initialize the gas, bulk aerosol, and modal aerosol lists. This step splits the
373 : ! input climate/diagnostic lists into the corresponding gas, bulk and modal aerosol
374 : ! lists.
375 1536 : if (masterproc) write(iulog,*) nl//subname//': Radiation constituent lists:'
376 18432 : do i = 0, N_DIAG
377 18432 : if (active_calls(i)) then
378 : call list_init1(namelist(i), gaslist(i), aerosollist(i), ma_list(i))
379 :
380 1538 : if (masterproc .and. verbose) then
381 2 : call print_lists(gaslist(i), aerosollist(i), ma_list(i))
382 : end if
383 :
384 : end if
385 : end do
386 :
387 1536 : if (masterproc .and. verbose) call print_modes(modes)
388 :
389 1536 : end subroutine rad_cnst_readnl
390 :
391 : !================================================================================================
392 :
393 1536 : subroutine rad_cnst_init()
394 :
395 : ! The initialization of the gas and aerosol lists is finished by
396 : ! 1) read the physprop files
397 : ! 2) find the index of each constituent in the constituent or physics buffer arrays
398 : ! 3) find the index of the aerosol constituents used to access its properties from the
399 : ! physprop module.
400 :
401 : integer :: i
402 : logical, parameter :: stricttest = .true.
403 : character(len=*), parameter :: subname = 'rad_cnst_init'
404 : !-----------------------------------------------------------------------------
405 :
406 : ! memory to point to if zero value requested
407 1536 : allocate(zero_cols(pcols,pver))
408 680448 : zero_cols = 0._r8
409 :
410 : ! Allocate storage for the physical properties of each aerosol; read properties from
411 : ! the data files.
412 1536 : call physprop_init()
413 :
414 : ! Start checking that specified radiative constituents are present in the constituent
415 : ! or physics buffer arrays.
416 1536 : if (masterproc) write(iulog,*) nl//subname//': checking for radiative constituents'
417 :
418 : ! Finish initializing the mode definitions.
419 1536 : call init_mode_comps(modes)
420 :
421 : ! Finish initializing the gas, bulk aerosol, and mode lists.
422 18432 : do i = 0, N_DIAG
423 18432 : if (active_calls(i)) then
424 : call list_init2(gaslist(i), aerosollist(i), ma_list(i))
425 : end if
426 : end do
427 :
428 : ! Check that all gases supported by the radiative transfer code have been specified.
429 : if (stricttest) then
430 13824 : do i = 1, nradgas
431 13824 : if (gaslist(0)%gas(i)%source .eq. 'Z' ) then
432 0 : call endrun(subname//': list of radiative gasses must include all radiation gasses for the climate specication')
433 : endif
434 : enddo
435 : endif
436 :
437 : ! Initialize history output of climate diagnostic quantities
438 1536 : call rad_gas_diag_init(gaslist(0))
439 1536 : call rad_aer_diag_init(aerosollist(0))
440 :
441 :
442 1536 : end subroutine rad_cnst_init
443 :
444 : !================================================================================================
445 :
446 7489224 : subroutine rad_cnst_get_gas(list_idx, gasname, state, pbuf, mmr)
447 :
448 : ! Return pointer to mass mixing ratio for the gas from the specified
449 : ! climate or diagnostic list.
450 :
451 : ! Arguments
452 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
453 : character(len=*), intent(in) :: gasname
454 : type(physics_state), target, intent(in) :: state
455 : type(physics_buffer_desc), pointer :: pbuf(:)
456 : real(r8), pointer :: mmr(:,:)
457 :
458 : ! Local variables
459 : integer :: lchnk
460 : integer :: igas
461 : integer :: idx
462 : character(len=1) :: source
463 : type(gaslist_t), pointer :: list
464 : character(len=*), parameter :: subname = 'rad_cnst_get_gas'
465 : !-----------------------------------------------------------------------------
466 :
467 7489224 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
468 7489224 : list => gaslist(list_idx)
469 : else
470 0 : write(iulog,*) subname//': list_idx =', list_idx
471 0 : call endrun(subname//': list_idx out of bounds')
472 : endif
473 :
474 7489224 : lchnk = state%lchnk
475 :
476 : ! Get index of gas in internal arrays. rad_gas_index will abort if the
477 : ! specified gasname is not recognized by the radiative transfer code.
478 7489224 : igas = rad_gas_index(trim(gasname))
479 :
480 : ! Get data source
481 7489224 : source = list%gas(igas)%source
482 7489224 : idx = list%gas(igas)%idx
483 749232 : select case( source )
484 : case ('A')
485 749232 : mmr => state%q(:,:,idx)
486 : case ('N')
487 6739992 : call pbuf_get_field(pbuf, idx, mmr)
488 : case ('Z')
489 7489224 : mmr => zero_cols
490 : end select
491 :
492 7489224 : end subroutine rad_cnst_get_gas
493 :
494 : !================================================================================================
495 :
496 0 : function rad_cnst_num_name(list_idx, spc_name_in, num_name_out, mode_out, spec_out ) result(found)
497 :
498 : ! for a given species name spc_name_in return (optionals):
499 : ! num_name_out -- corresponding number density species name
500 : ! mode_out -- corresponding mode number
501 : ! spec_out -- corresponding species number within the mode
502 :
503 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
504 : character(len=*),intent(in) :: spc_name_in
505 : character(len=*),intent(out):: num_name_out
506 : integer,optional,intent(out):: mode_out
507 : integer,optional,intent(out):: spec_out
508 :
509 : logical :: found
510 :
511 : ! Local variables
512 : type(modelist_t), pointer :: m_list ! local pointer to mode list of interest
513 : integer :: n,m, mm
514 : integer :: nmodes
515 : integer :: nspecs
516 : character(len= 32) :: spec_name
517 :
518 0 : found = .false.
519 :
520 0 : m_list => ma_list(list_idx)
521 0 : nmodes = m_list%nmodes
522 :
523 0 : do n = 1,nmodes
524 0 : mm = m_list%idx(n)
525 0 : nspecs = modes%comps(mm)%nspec
526 0 : do m = 1,nspecs
527 0 : spec_name = modes%comps(mm)%camname_mmr_a(m)
528 0 : if (spc_name_in == spec_name) then
529 0 : num_name_out = modes%comps(mm)%camname_num_a
530 0 : found = .true.
531 0 : if (present(mode_out)) then
532 0 : mode_out = n
533 : endif
534 0 : if (present(spec_out)) then
535 0 : spec_out = m
536 : endif
537 0 : return
538 : endif
539 : enddo
540 : enddo
541 :
542 : return
543 :
544 0 : end function
545 :
546 : !================================================================================================
547 :
548 821952 : subroutine rad_cnst_get_info(list_idx, gasnames, aernames, &
549 : use_data_o3, ngas, naero, nmodes)
550 :
551 : ! Return info about gas and aerosol lists
552 :
553 : ! Arguments
554 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
555 : character(len=64), optional, intent(out) :: gasnames(:)
556 : character(len=64), optional, intent(out) :: aernames(:)
557 : logical, optional, intent(out) :: use_data_o3
558 : integer, optional, intent(out) :: naero
559 : integer, optional, intent(out) :: ngas
560 : integer, optional, intent(out) :: nmodes
561 :
562 : ! Local variables
563 : type(gaslist_t), pointer :: g_list ! local pointer to gas list of interest
564 : type(aerlist_t), pointer :: a_list ! local pointer to aerosol list of interest
565 : type(modelist_t), pointer :: m_list ! local pointer to mode list of interest
566 :
567 : integer :: i
568 : integer :: arrlen ! length of assumed shape array
569 : integer :: gaslen ! length of assumed shape array
570 : integer :: igas ! index of a gas in the gas list
571 : character(len=1) :: source ! A for state, N for pbuf, Z for zero
572 :
573 : character(len=*), parameter :: subname = 'rad_cnst_get_info'
574 : !-----------------------------------------------------------------------------
575 :
576 821952 : g_list => gaslist(list_idx)
577 821952 : a_list => aerosollist(list_idx)
578 821952 : m_list => ma_list(list_idx)
579 :
580 : ! number of bulk aerosols in list
581 821952 : if (present(naero)) then
582 818880 : naero = a_list%numaerosols
583 : endif
584 :
585 : ! number of aerosol modes in list
586 821952 : if (present(nmodes)) then
587 820416 : nmodes = m_list%nmodes
588 : endif
589 :
590 : ! number of gases in list
591 821952 : if (present(ngas)) then
592 0 : ngas = g_list%ngas
593 : endif
594 :
595 : ! names of aerosols in list
596 821952 : if (present(aernames)) then
597 :
598 : ! check that output array is long enough
599 1536 : arrlen = size(aernames)
600 1536 : if (arrlen < a_list%numaerosols) then
601 0 : write(iulog,*) subname//': ERROR: naero=', a_list%numaerosols, ' arrlen=', arrlen
602 0 : call endrun(subname//': ERROR: aernames too short')
603 : end if
604 :
605 1536 : do i = 1, a_list%numaerosols
606 1536 : aernames(i) = a_list%aer(i)%camname
607 : end do
608 :
609 : end if
610 :
611 : ! names of gas in list
612 821952 : if (present(gasnames)) then
613 :
614 : ! check that output array is long enough
615 0 : gaslen = size(gasnames)
616 0 : if (gaslen < g_list%ngas) then
617 0 : write(iulog,*) subname//': ERROR: ngas=', g_list%ngas, ' gaslen=', gaslen
618 0 : call endrun(subname//': ERROR: gasnames too short')
619 : end if
620 :
621 0 : do i = 1, g_list%ngas
622 0 : gasnames(i) = g_list%gas(i)%camname
623 : end do
624 :
625 : end if
626 :
627 : ! Does the climate calculation use data ozone?
628 821952 : if (present(use_data_o3)) then
629 :
630 : ! get index of O3 in gas list
631 0 : igas = rad_gas_index('O3')
632 :
633 : ! Get data source
634 0 : source = g_list%gas(igas)%source
635 :
636 0 : use_data_o3 = .false.
637 0 : if (source == 'N') use_data_o3 = .true.
638 : endif
639 :
640 821952 : end subroutine rad_cnst_get_info
641 :
642 : !================================================================================================
643 :
644 0 : subroutine rad_cnst_get_info_by_mode(list_idx, m_idx, &
645 0 : mode_type, num_name, num_name_cw, nspec)
646 :
647 : ! Return info about modal aerosol lists
648 :
649 : ! Arguments
650 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
651 : integer, intent(in) :: m_idx ! index of mode in the specified list
652 : character(len=32), optional, intent(out) :: mode_type ! type of mode (as used in MAM code)
653 : character(len=32), optional, intent(out) :: num_name ! name of interstitial number mixing ratio
654 : character(len=32), optional, intent(out) :: num_name_cw ! name of cloud borne number mixing ratio
655 : integer, optional, intent(out) :: nspec ! number of species in the mode
656 :
657 : ! Local variables
658 : type(modelist_t), pointer :: m_list ! local pointer to mode list of interest
659 :
660 : integer :: nmodes
661 : integer :: mm
662 :
663 : character(len=*), parameter :: subname = 'rad_cnst_get_info_by_mode'
664 : !-----------------------------------------------------------------------------
665 :
666 0 : m_list => ma_list(list_idx)
667 :
668 : ! check for valid mode index
669 0 : nmodes = m_list%nmodes
670 0 : if (m_idx < 1 .or. m_idx > nmodes) then
671 0 : write(iulog,*) subname//': ERROR - invalid mode index: ', m_idx
672 0 : call endrun(subname//': ERROR - invalid mode index')
673 : end if
674 :
675 : ! get index into the mode definition object
676 0 : mm = m_list%idx(m_idx)
677 :
678 : ! mode type
679 0 : if (present(mode_type)) then
680 0 : mode_type = modes%types(mm)
681 : endif
682 :
683 : ! number of species in the mode
684 0 : if (present(nspec)) then
685 0 : nspec = modes%comps(mm)%nspec
686 : endif
687 :
688 : ! name of interstitial number mixing ratio
689 0 : if (present(num_name)) then
690 0 : num_name = modes%comps(mm)%camname_num_a
691 : endif
692 :
693 : ! name of cloud borne number mixing ratio
694 0 : if (present(num_name_cw)) then
695 0 : num_name_cw = modes%comps(mm)%camname_num_c
696 : endif
697 :
698 821952 : end subroutine rad_cnst_get_info_by_mode
699 :
700 : !================================================================================================
701 :
702 0 : subroutine rad_cnst_get_info_by_mode_spec(list_idx, m_idx, s_idx, &
703 0 : spec_type, spec_name, spec_name_cw)
704 :
705 : ! Return info about modal aerosol lists
706 :
707 : ! Arguments
708 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
709 : integer, intent(in) :: m_idx ! index of mode in the specified list
710 : integer, intent(in) :: s_idx ! index of specie in the specified mode
711 : character(len=32), optional, intent(out) :: spec_type ! type of specie
712 : character(len=32), optional, intent(out) :: spec_name ! name of interstitial specie
713 : character(len=32), optional, intent(out) :: spec_name_cw ! name of cloud borne specie
714 :
715 : ! Local variables
716 : type(modelist_t), pointer :: m_list ! local pointer to mode list of interest
717 :
718 : integer :: nmodes
719 : integer :: nspec
720 : integer :: mm
721 :
722 : character(len=*), parameter :: subname = 'rad_cnst_get_info_by_mode_spec'
723 : !-----------------------------------------------------------------------------
724 :
725 0 : m_list => ma_list(list_idx)
726 :
727 : ! check for valid mode index
728 0 : nmodes = m_list%nmodes
729 0 : if (m_idx < 1 .or. m_idx > nmodes) then
730 0 : write(iulog,*) subname//': ERROR - invalid mode index: ', m_idx
731 0 : call endrun(subname//': ERROR - invalid mode index')
732 : end if
733 :
734 : ! get index into the mode definition object
735 0 : mm = m_list%idx(m_idx)
736 :
737 : ! check for valid specie index
738 0 : nspec = modes%comps(mm)%nspec
739 0 : if (s_idx < 1 .or. s_idx > nspec) then
740 0 : write(iulog,*) subname//': ERROR - invalid specie index: ', s_idx
741 0 : call endrun(subname//': ERROR - invalid specie index')
742 : end if
743 :
744 : ! specie type
745 0 : if (present(spec_type)) then
746 0 : spec_type = modes%comps(mm)%type(s_idx)
747 : endif
748 :
749 : ! interstitial specie name
750 0 : if (present(spec_name)) then
751 0 : spec_name = modes%comps(mm)%camname_mmr_a(s_idx)
752 : endif
753 :
754 : ! cloud borne specie name
755 0 : if (present(spec_name_cw)) then
756 0 : spec_name_cw = modes%comps(mm)%camname_mmr_c(s_idx)
757 : endif
758 :
759 0 : end subroutine rad_cnst_get_info_by_mode_spec
760 :
761 : !================================================================================================
762 :
763 0 : subroutine rad_cnst_get_info_by_spectype(list_idx, spectype, mode_idx, spec_idx)
764 :
765 : ! Return info about modes in the specified climate/diagnostics list
766 :
767 : ! Arguments
768 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
769 : character(len=*), intent(in) :: spectype ! species type
770 : integer, optional, intent(out) :: mode_idx ! index of a mode that contains a specie of spectype
771 : integer, optional, intent(out) :: spec_idx ! index of the species of spectype
772 :
773 : ! Local variables
774 : type(modelist_t), pointer :: m_list ! local pointer to mode list of interest
775 :
776 : integer :: i, nmodes, m_idx, nspec, ispec
777 : logical :: found_spectype
778 :
779 : character(len=*), parameter :: subname = 'rad_cnst_get_info_by_spectype'
780 : !-----------------------------------------------------------------------------
781 :
782 0 : m_list => ma_list(list_idx)
783 :
784 : ! number of modes in specified list
785 0 : nmodes = m_list%nmodes
786 :
787 : ! loop through modes in specified climate/diagnostic list
788 0 : found_spectype = .false.
789 0 : do i = 1, nmodes
790 :
791 : ! get index of the mode in the definition object
792 0 : m_idx = m_list%idx(i)
793 :
794 : ! number of species in the mode
795 0 : nspec = modes%comps(m_idx)%nspec
796 :
797 : ! loop through species looking for spectype
798 0 : do ispec = 1, nspec
799 :
800 0 : if (trim(modes%comps(m_idx)%type(ispec)) == trim(spectype)) then
801 0 : if (present(mode_idx)) mode_idx = i
802 0 : if (present(spec_idx)) spec_idx = ispec
803 0 : found_spectype = .true.
804 0 : exit
805 : end if
806 : end do
807 :
808 0 : if (found_spectype) exit
809 : end do
810 :
811 0 : if (.not. found_spectype) then
812 0 : if (present(mode_idx)) mode_idx = -1
813 0 : if (present(spec_idx)) spec_idx = -1
814 : end if
815 :
816 0 : end subroutine rad_cnst_get_info_by_spectype
817 :
818 : !================================================================================================
819 :
820 0 : function rad_cnst_get_mode_idx(list_idx, mode_type) result(mode_idx)
821 :
822 : ! Return mode index of the specified type in the specified climate/diagnostics list.
823 : ! Return -1 if not found.
824 :
825 : ! Arguments
826 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
827 : character(len=*), intent(in) :: mode_type ! mode type
828 :
829 : ! Return value
830 : integer :: mode_idx ! mode index
831 :
832 : ! Local variables
833 : type(modelist_t), pointer :: m_list
834 :
835 : integer :: i, nmodes, m_idx
836 :
837 : character(len=*), parameter :: subname = 'rad_cnst_get_mode_idx'
838 : !-----------------------------------------------------------------------------
839 :
840 : ! if mode type not found return -1
841 0 : mode_idx = -1
842 :
843 : ! specified mode list
844 0 : m_list => ma_list(list_idx)
845 :
846 : ! number of modes in specified list
847 0 : nmodes = m_list%nmodes
848 :
849 : ! loop through modes in specified climate/diagnostic list
850 0 : do i = 1, nmodes
851 :
852 : ! get index of the mode in the definition object
853 0 : m_idx = m_list%idx(i)
854 :
855 : ! look in mode definition object (modes) for the mode types
856 0 : if (trim(modes%types(m_idx)) == trim(mode_type)) then
857 0 : mode_idx = i
858 0 : exit
859 : end if
860 : end do
861 :
862 0 : end function rad_cnst_get_mode_idx
863 :
864 : !================================================================================================
865 :
866 0 : function rad_cnst_get_spec_idx(list_idx, mode_idx, spec_type) result(spec_idx)
867 :
868 : ! Return specie index of the specified type in the specified mode of the specified
869 : ! climate/diagnostics list. Return -1 if not found.
870 :
871 : ! Arguments
872 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
873 : integer, intent(in) :: mode_idx ! mode index
874 : character(len=*), intent(in) :: spec_type ! specie type
875 :
876 : ! Return value
877 : integer :: spec_idx ! specie index
878 :
879 : ! Local variables
880 : type(modelist_t), pointer :: m_list
881 : type(mode_component_t), pointer :: mode_comps
882 :
883 : integer :: i, m_idx, nspec
884 :
885 : character(len=*), parameter :: subname = 'rad_cnst_get_spec_idx'
886 : !-----------------------------------------------------------------------------
887 :
888 : ! if specie type not found return -1
889 0 : spec_idx = -1
890 :
891 : ! modes in specified list
892 0 : m_list => ma_list(list_idx)
893 :
894 : ! get index of the specified mode in the definition object
895 0 : m_idx = m_list%idx(mode_idx)
896 :
897 : ! object containing the components of the mode
898 0 : mode_comps => modes%comps(m_idx)
899 :
900 : ! number of species in specified mode
901 0 : nspec = mode_comps%nspec
902 :
903 : ! loop through species in specified mode
904 0 : do i = 1, nspec
905 :
906 : ! look in mode definition object (modes) for the mode types
907 0 : if (trim(mode_comps%type(i)) == trim(spec_type)) then
908 0 : spec_idx = i
909 0 : exit
910 : end if
911 : end do
912 :
913 0 : end function rad_cnst_get_spec_idx
914 :
915 : !================================================================================================
916 :
917 0 : subroutine rad_cnst_get_call_list(call_list)
918 :
919 : ! Return info about which climate/diagnostic calculations are requested
920 :
921 : ! Arguments
922 : logical, intent(out) :: call_list(0:N_DIAG)
923 : !-----------------------------------------------------------------------------
924 :
925 0 : call_list(:) = active_calls(:)
926 :
927 0 : end subroutine rad_cnst_get_call_list
928 :
929 : !================================================================================================
930 :
931 749232 : subroutine rad_cnst_out(list_idx, state, pbuf)
932 :
933 : ! Output the mass per layer, and total column burdens for gas and aerosol
934 : ! constituents in either the climate or diagnostic lists
935 :
936 : ! Arguments
937 : integer, intent(in) :: list_idx
938 : type(physics_state), target, intent(in) :: state
939 : type(physics_buffer_desc), pointer :: pbuf(:)
940 :
941 :
942 : ! Local variables
943 : integer :: i, naer, ngas, lchnk, ncol
944 : integer :: idx
945 : character(len=1) :: source
946 : character(len=32) :: name, cbname
947 : real(r8) :: mass(pcols,pver)
948 : real(r8) :: cb(pcols)
949 749232 : real(r8), pointer :: mmr(:,:)
950 : type(aerlist_t), pointer :: aerlist
951 : type(gaslist_t), pointer :: g_list
952 : character(len=*), parameter :: subname = 'rad_cnst_out'
953 : !-----------------------------------------------------------------------------
954 :
955 749232 : lchnk = state%lchnk
956 749232 : ncol = state%ncol
957 :
958 : ! Associate pointer with requested aerosol list
959 749232 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
960 749232 : aerlist => aerosollist(list_idx)
961 : else
962 0 : write(iulog,*) subname//': list_idx = ', list_idx
963 0 : call endrun(subname//': list_idx out of range')
964 : endif
965 :
966 749232 : naer = aerlist%numaerosols
967 749232 : do i = 1, naer
968 :
969 0 : source = aerlist%aer(i)%source
970 0 : idx = aerlist%aer(i)%idx
971 0 : name = aerlist%aer(i)%mass_name
972 : ! construct name for column burden field by replacing the 'm_' prefix by 'cb_'
973 0 : cbname = 'cb_' // name(3:len_trim(name))
974 :
975 0 : select case( source )
976 : case ('A')
977 0 : mmr => state%q(:,:,idx)
978 : case ('N')
979 0 : call pbuf_get_field(pbuf, idx, mmr)
980 : end select
981 :
982 0 : mass(:ncol,:) = mmr(:ncol,:) * state%pdeldry(:ncol,:) * rga
983 0 : call outfld(trim(name), mass, pcols, lchnk)
984 :
985 0 : cb(:ncol) = sum(mass(:ncol,:),2)
986 749232 : call outfld(trim(cbname), cb, pcols, lchnk)
987 :
988 : end do
989 :
990 : ! Associate pointer with requested gas list
991 749232 : g_list => gaslist(list_idx)
992 :
993 749232 : ngas = g_list%ngas
994 6743088 : do i = 1, ngas
995 :
996 5993856 : source = g_list%gas(i)%source
997 5993856 : idx = g_list%gas(i)%idx
998 5993856 : name = g_list%gas(i)%mass_name
999 5993856 : cbname = 'cb_' // name(3:len_trim(name))
1000 749232 : select case( source )
1001 : case ('A')
1002 749232 : mmr => state%q(:,:,idx)
1003 : case ('N')
1004 5993856 : call pbuf_get_field(pbuf, idx, mmr)
1005 : end select
1006 :
1007 2608163712 : mass(:ncol,:) = mmr(:ncol,:) * state%pdeldry(:ncol,:) * rga
1008 5993856 : call outfld(trim(name), mass, pcols, lchnk)
1009 :
1010 2546413056 : cb(:ncol) = sum(mass(:ncol,:),2)
1011 6743088 : call outfld(trim(cbname), cb, pcols, lchnk)
1012 :
1013 : end do
1014 :
1015 749232 : end subroutine rad_cnst_out
1016 :
1017 : !================================================================================================
1018 : ! Private methods
1019 : !================================================================================================
1020 :
1021 1536 : subroutine init_mode_comps(modes)
1022 :
1023 : ! Initialize the mode definitions by looking up the relevent indices in the
1024 : ! constituent and pbuf arrays, and getting the physprop IDs
1025 :
1026 : ! Arguments
1027 : type(modes_t), intent(inout) :: modes
1028 :
1029 : ! Local variables
1030 : integer :: m, ispec, nspec
1031 :
1032 : character(len=*), parameter :: routine = 'init_modes'
1033 : !-----------------------------------------------------------------------------
1034 :
1035 1536 : do m = 1, modes%nmodes
1036 :
1037 : ! indices for number mixing ratio components
1038 0 : modes%comps(m)%idx_num_a = get_cam_idx(modes%comps(m)%source_num_a, modes%comps(m)%camname_num_a, routine)
1039 0 : modes%comps(m)%idx_num_c = get_cam_idx(modes%comps(m)%source_num_c, modes%comps(m)%camname_num_c, routine)
1040 :
1041 : ! allocate memory for species
1042 0 : nspec = modes%comps(m)%nspec
1043 : allocate( &
1044 : modes%comps(m)%idx_mmr_a(nspec), &
1045 0 : modes%comps(m)%idx_mmr_c(nspec), &
1046 0 : modes%comps(m)%idx_props(nspec) )
1047 :
1048 1536 : do ispec = 1, nspec
1049 :
1050 : ! indices for species mixing ratio components
1051 0 : modes%comps(m)%idx_mmr_a(ispec) = get_cam_idx(modes%comps(m)%source_mmr_a(ispec), &
1052 0 : modes%comps(m)%camname_mmr_a(ispec), routine)
1053 0 : modes%comps(m)%idx_mmr_c(ispec) = get_cam_idx(modes%comps(m)%source_mmr_c(ispec), &
1054 0 : modes%comps(m)%camname_mmr_c(ispec), routine)
1055 :
1056 : ! get physprop ID
1057 0 : modes%comps(m)%idx_props(ispec) = physprop_get_id(modes%comps(m)%props(ispec))
1058 0 : if (modes%comps(m)%idx_props(ispec) == -1) then
1059 0 : call endrun(routine//' : ERROR idx not found for '//trim(modes%comps(m)%props(ispec)))
1060 : end if
1061 :
1062 : end do
1063 :
1064 : end do
1065 :
1066 1536 : end subroutine init_mode_comps
1067 :
1068 : !================================================================================================
1069 :
1070 12288 : integer function get_cam_idx(source, name, routine)
1071 :
1072 : ! get index of name in internal CAM array; either the constituent array
1073 : ! or the physics buffer
1074 :
1075 : character(len=*), intent(in) :: source
1076 : character(len=*), intent(in) :: name
1077 : character(len=*), intent(in) :: routine ! name of calling routine
1078 :
1079 : integer :: idx
1080 : integer :: errcode
1081 : !-----------------------------------------------------------------------------
1082 :
1083 12288 : if (source(1:1) == 'N') then
1084 :
1085 10752 : idx = pbuf_get_index(trim(name),errcode)
1086 10752 : if (errcode < 0) then
1087 0 : call endrun(routine//' ERROR: cannot find physics buffer field '//trim(name))
1088 : end if
1089 :
1090 1536 : else if (source(1:1) == 'A') then
1091 :
1092 1536 : call cnst_get_ind(trim(name), idx, abort=.false.)
1093 1536 : if (idx < 0) then
1094 0 : call endrun(routine//' ERROR: cannot find constituent field '//trim(name))
1095 : end if
1096 :
1097 0 : else if (source(1:1) == 'Z') then
1098 :
1099 0 : idx = -1
1100 :
1101 : else
1102 :
1103 0 : call endrun(routine//' ERROR: invalid source for specie '//trim(name))
1104 :
1105 : end if
1106 :
1107 12288 : get_cam_idx = idx
1108 :
1109 12288 : end function get_cam_idx
1110 :
1111 : !================================================================================================
1112 :
1113 1536 : subroutine list_init1(namelist, gaslist, aerlist, ma_list)
1114 :
1115 : ! Initialize the gas and bulk and modal aerosol lists with the
1116 : ! entities specified in the climate or diagnostic lists.
1117 :
1118 : ! This first phase initialization just sets the information that
1119 : ! is available at the time the namelist is read.
1120 :
1121 : type(rad_cnst_namelist_t), intent(in) :: namelist ! parsed namelist input for climate or diagnostic lists
1122 :
1123 : type(gaslist_t), intent(inout) :: gaslist
1124 : type(aerlist_t), intent(inout) :: aerlist
1125 : type(modelist_t), intent(inout) :: ma_list
1126 :
1127 :
1128 : ! Local variables
1129 : integer :: ii, m, naero, nmodes
1130 : integer :: igas, ba_idx, ma_idx
1131 : integer :: istat
1132 : character(len=*), parameter :: routine = 'list_init1'
1133 : !-----------------------------------------------------------------------------
1134 :
1135 : ! nradgas is set by the radiative transfer code
1136 1536 : gaslist%ngas = nradgas
1137 :
1138 : ! Determine the number of bulk aerosols and aerosol modes in the list
1139 1536 : naero = 0
1140 1536 : nmodes = 0
1141 13824 : do ii = 1, namelist%ncnst
1142 12288 : if (trim(namelist%type(ii)) == 'A') naero = naero + 1
1143 13824 : if (trim(namelist%type(ii)) == 'M') nmodes = nmodes + 1
1144 : end do
1145 1536 : aerlist%numaerosols = naero
1146 1536 : ma_list%nmodes = nmodes
1147 :
1148 : ! allocate storage for the aerosol, gas, and mode lists
1149 : allocate( &
1150 : aerlist%aer(aerlist%numaerosols), &
1151 : gaslist%gas(gaslist%ngas), &
1152 : ma_list%idx(ma_list%nmodes), &
1153 : ma_list%physprop_files(ma_list%nmodes), &
1154 : ma_list%idx_props(ma_list%nmodes), &
1155 9216 : stat=istat)
1156 1536 : if (istat /= 0) call endrun(routine//': allocate ERROR; aero and gas list components')
1157 :
1158 1536 : if (masterproc .and. verbose) then
1159 2 : if (len_trim(gaslist%list_id) == 0) then
1160 2 : write(iulog,*) nl//' '//routine//': namelist input for climate list'
1161 : else
1162 0 : write(iulog,*) nl//' '//routine//': namelist input for diagnostic list:'//gaslist%list_id
1163 : end if
1164 : end if
1165 :
1166 : ! Loop over the radiatively active components specified in the namelist
1167 1536 : ba_idx = 0
1168 1536 : ma_idx = 0
1169 13824 : do ii = 1, namelist%ncnst
1170 :
1171 12288 : if (masterproc .and. verbose) &
1172 0 : write(iulog,*) " rad namelist spec: "// trim(namelist%source(ii)) &
1173 16 : //":"//trim(namelist%camname(ii))//":"//trim(namelist%radname(ii))
1174 :
1175 : ! Check that the source specifier is legal.
1176 0 : if (namelist%source(ii) /= 'A' .and. namelist%source(ii) /= 'M' .and. &
1177 12288 : namelist%source(ii) /= 'N' .and. namelist%source(ii) /= 'Z' ) then
1178 : call endrun(routine//": source must either be A, M, N or Z:"//&
1179 0 : " illegal specifier in namelist input: "//namelist%source(ii))
1180 : end if
1181 :
1182 : ! Add component to appropriate list (gas, modal or bulk aerosol)
1183 13824 : if (namelist%type(ii) == 'A') then
1184 :
1185 : ! Add to bulk aerosol list
1186 0 : ba_idx = ba_idx + 1
1187 :
1188 0 : aerlist%aer(ba_idx)%source = namelist%source(ii)
1189 0 : aerlist%aer(ba_idx)%camname = namelist%camname(ii)
1190 0 : aerlist%aer(ba_idx)%physprop_file = namelist%radname(ii)
1191 :
1192 12288 : else if (namelist%type(ii) == 'M') then
1193 :
1194 : ! Add to modal aerosol list
1195 0 : ma_idx = ma_idx + 1
1196 :
1197 : ! Look through the mode definitions for the name of the specified mode. The
1198 : ! index into the modes object all the information relevent to the mode definition.
1199 0 : ma_list%idx(ma_idx) = -1
1200 0 : do m = 1, modes%nmodes
1201 0 : if (trim(namelist%camname(ii)) == trim(modes%names(m))) then
1202 0 : ma_list%idx(ma_idx) = m
1203 0 : exit
1204 : end if
1205 : end do
1206 0 : if (ma_list%idx(ma_idx) == -1) &
1207 0 : call endrun(routine//' ERROR cannot find mode name '//trim(namelist%camname(ii)))
1208 :
1209 : ! Also save the name of the physprop file
1210 0 : ma_list%physprop_files(ma_idx) = namelist%radname(ii)
1211 :
1212 : else
1213 :
1214 : ! Add to gas list
1215 :
1216 : ! The radiative transfer code requires the input of a specific set of gases
1217 : ! which is hardwired into the code. The CAM interface to the RT code uses
1218 : ! the names in the radconstants module to refer to these gases. The user
1219 : ! interface (namelist) also uses these names to identify the gases treated
1220 : ! by the RT code. We use the index order set in radconstants for convenience
1221 : ! only.
1222 :
1223 : ! First check that the gas name specified by the user is allowed.
1224 : ! rad_gas_index will abort on illegal names.
1225 12288 : igas = rad_gas_index(namelist%radname(ii))
1226 :
1227 : ! Set values in the igas index
1228 12288 : gaslist%gas(igas)%source = namelist%source(ii)
1229 12288 : gaslist%gas(igas)%camname = namelist%camname(ii)
1230 :
1231 : end if
1232 : end do
1233 :
1234 1536 : end subroutine list_init1
1235 :
1236 : !================================================================================================
1237 :
1238 1536 : subroutine list_init2(gaslist, aerlist, ma_list)
1239 :
1240 : ! Final initialization phase gets the component indices in the constituent array
1241 : ! and the physics buffer, and indices into physprop module.
1242 :
1243 : type(gaslist_t), intent(inout) :: gaslist
1244 : type(aerlist_t), intent(inout) :: aerlist
1245 : type(modelist_t), intent(inout) :: ma_list
1246 :
1247 : ! Local variables
1248 : integer :: i
1249 : character(len=*), parameter :: routine = 'list_init2'
1250 : !-----------------------------------------------------------------------------
1251 :
1252 : ! Loop over gases
1253 13824 : do i = 1, gaslist%ngas
1254 :
1255 : ! locate the specie mixing ratio in the pbuf or state
1256 13824 : gaslist%gas(i)%idx = get_cam_idx(gaslist%gas(i)%source, gaslist%gas(i)%camname, routine)
1257 :
1258 : end do
1259 :
1260 : ! Loop over bulk aerosols
1261 1536 : do i = 1, aerlist%numaerosols
1262 :
1263 : ! locate the specie mixing ratio in the pbuf or state
1264 0 : aerlist%aer(i)%idx = get_cam_idx(aerlist%aer(i)%source, aerlist%aer(i)%camname, routine)
1265 :
1266 : ! get the physprop_id from the phys_prop module
1267 1536 : aerlist%aer(i)%physprop_id = physprop_get_id(aerlist%aer(i)%physprop_file)
1268 :
1269 : end do
1270 :
1271 : ! Loop over modes
1272 1536 : do i = 1, ma_list%nmodes
1273 :
1274 : ! get the physprop_id from the phys_prop module
1275 1536 : ma_list%idx_props(i) = physprop_get_id(ma_list%physprop_files(i))
1276 :
1277 : end do
1278 :
1279 1536 : end subroutine list_init2
1280 :
1281 : !================================================================================================
1282 :
1283 1536 : subroutine rad_gas_diag_init(glist)
1284 :
1285 : ! Add diagnostic fields to the master fieldlist.
1286 :
1287 : type(gaslist_t), intent(inout) :: glist
1288 :
1289 : integer :: i, ngas
1290 : character(len=64) :: name
1291 : character(len=2) :: list_id
1292 : character(len=4) :: suffix
1293 : character(len=128):: long_name
1294 : character(len=32) :: long_name_description
1295 : !-----------------------------------------------------------------------------
1296 :
1297 1536 : ngas = glist%ngas
1298 1536 : if (ngas == 0) return
1299 :
1300 : ! Determine whether this is a climate or diagnostic list.
1301 1536 : list_id = glist%list_id
1302 1536 : if (len_trim(list_id) == 0) then
1303 1536 : suffix = '_c'
1304 1536 : long_name_description = ' used in climate calculation'
1305 : else
1306 0 : suffix = '_d' // list_id
1307 0 : long_name_description = ' used in diagnostic calculation'
1308 : end if
1309 :
1310 13824 : do i = 1, ngas
1311 :
1312 : ! construct names for mass per layer diagnostics
1313 12288 : name = 'm_' // trim(glist%gas(i)%camname) // trim(suffix)
1314 12288 : glist%gas(i)%mass_name = name
1315 12288 : long_name = trim(glist%gas(i)%camname)//' mass per layer'//long_name_description
1316 24576 : call addfld(trim(name), (/ 'lev' /), 'A', 'kg/m^2', trim(long_name))
1317 :
1318 : ! construct names for column burden diagnostics
1319 12288 : name = 'cb_' // trim(glist%gas(i)%camname) // trim(suffix)
1320 12288 : long_name = trim(glist%gas(i)%camname)//' column burden'//long_name_description
1321 12288 : call addfld(trim(name), horiz_only, 'A', 'kg/m^2', trim(long_name))
1322 :
1323 : ! error check for name length
1324 13824 : if (len_trim(name) > fieldname_len) then
1325 0 : write(iulog,*) 'rad_gas_diag_init: '//trim(name)//' longer than ', fieldname_len, ' characters'
1326 0 : call endrun('rad_gas_diag_init: name too long: '//trim(name))
1327 : end if
1328 :
1329 : end do
1330 :
1331 : end subroutine rad_gas_diag_init
1332 :
1333 : !================================================================================================
1334 :
1335 1536 : subroutine rad_aer_diag_init(alist)
1336 :
1337 : ! Add diagnostic fields to the master fieldlist.
1338 :
1339 : type(aerlist_t), intent(inout) :: alist
1340 :
1341 : integer :: i, naer
1342 : character(len=64) :: name
1343 : character(len=2) :: list_id
1344 : character(len=4) :: suffix
1345 : character(len=128):: long_name
1346 : character(len=32) :: long_name_description
1347 : !-----------------------------------------------------------------------------
1348 :
1349 1536 : naer = alist%numaerosols
1350 1536 : if (naer == 0) return
1351 :
1352 : ! Determine whether this is a climate or diagnostic list.
1353 0 : list_id = alist%list_id
1354 0 : if (len_trim(list_id) == 0) then
1355 0 : suffix = '_c'
1356 0 : long_name_description = ' used in climate calculation'
1357 : else
1358 0 : suffix = '_d' // list_id
1359 0 : long_name_description = ' used in diagnostic calculation'
1360 : end if
1361 :
1362 0 : do i = 1, naer
1363 :
1364 : ! construct names for mass per layer diagnostic fields
1365 0 : name = 'm_' // trim(alist%aer(i)%camname) // trim(suffix)
1366 0 : alist%aer(i)%mass_name = name
1367 0 : long_name = trim(alist%aer(i)%camname)//' mass per layer'//long_name_description
1368 0 : call addfld(trim(name), (/ 'lev' /), 'A', 'kg/m^2', trim(long_name))
1369 :
1370 : ! construct names for column burden diagnostic fields
1371 0 : name = 'cb_' // trim(alist%aer(i)%camname) // trim(suffix)
1372 0 : long_name = trim(alist%aer(i)%camname)//' column burden'//long_name_description
1373 0 : call addfld(trim(name), horiz_only, 'A', 'kg/m^2', trim(long_name))
1374 :
1375 : ! error check for name length
1376 0 : if (len_trim(name) > fieldname_len) then
1377 0 : write(iulog,*) 'rad_aer_diag_init: '//trim(name)//' longer than ', fieldname_len, ' characters'
1378 0 : call endrun('rad_aer_diag_init: name too long: '//trim(name))
1379 : end if
1380 :
1381 : end do
1382 :
1383 : end subroutine rad_aer_diag_init
1384 :
1385 :
1386 : !================================================================================================
1387 :
1388 1536 : subroutine parse_mode_defs(nl_in, modes)
1389 :
1390 : ! Parse the mode definition specifiers. The specifiers are of the form:
1391 : !
1392 : ! 'mode_name:mode_type:=',
1393 : ! 'source_num_a:camname_num_a:source_num_c:camname_num_c:num_mr:+',
1394 : ! 'source_mmr_a:camname_mmr_a:source_mmr_c:camname_mmr_c:spec_type:prop_file[:+]'[,]
1395 : ! ['source_mmr_a:camname_mmr_a:source_mmr_c:camname_mmr_c:spec_type:prop_file][:+][']
1396 : !
1397 : ! where the ':' separated fields are:
1398 : ! mode_name -- name of the mode.
1399 : ! mode_type -- type of mode. Valid values are from the MAM code.
1400 : ! = -- this line terminator identifies the initial string in a
1401 : ! mode definition
1402 : ! + -- this line terminator indicates that the mode definition is
1403 : ! continued in the next string
1404 : ! source_num_a -- Source of interstitial number mixing ratio, 'A', 'N', or 'Z'
1405 : ! camname_num_a -- the name of the interstitial number component. This name must be
1406 : ! registered in the constituent arrays when source=A or in the
1407 : ! physics buffer when source=N
1408 : ! source_num_c -- Source of cloud borne number mixing ratio, 'A', 'N', or 'Z'
1409 : ! camname_num_c -- the name of the cloud borne number component. This name must be
1410 : ! registered in the constituent arrays when source=A or in the
1411 : ! physics buffer when source=N
1412 : ! source_mmr_a -- Source of interstitial specie mass mixing ratio, 'A', 'N' or 'Z'
1413 : ! camname_mmr_a -- the name of the interstitial specie. This name must be
1414 : ! registered in the constituent arrays when source=A or in the
1415 : ! physics buffer when source=N
1416 : ! source_mmr_c -- Source of cloud borne specie mass mixing ratio, 'A', 'N' or 'Z'
1417 : ! camname_mmr_c -- the name of the cloud borne specie. This name must be
1418 : ! registered in the constituent arrays when source=A or in the
1419 : ! physics buffer when source=N
1420 : ! spec_type -- species type. Valid values far from the MAM code, except that
1421 : ! the value 'num_mr' designates a number mixing ratio and has no
1422 : ! associated field for the prop_file. There can only be one entry
1423 : ! with the num_mr type in a mode definition.
1424 : ! prop_file -- For aerosol species this is a filename, which is
1425 : ! identified by a ".nc" suffix. The file contains optical and
1426 : ! other physical properties of the aerosol.
1427 : !
1428 : ! A mode definition must contain only 1 string for the number mixing ratio components
1429 : ! and at least 1 string for the species.
1430 :
1431 :
1432 : character(len=*), intent(inout) :: nl_in(:) ! namelist input (blanks are removed on output)
1433 : type(modes_t), intent(inout) :: modes ! structure containing parsed input
1434 :
1435 : ! Local variables
1436 : integer :: m
1437 : integer :: istat
1438 : integer :: nmodes, nstr
1439 : integer :: mbeg, mcur
1440 : integer :: nspec, ispec
1441 : integer :: strlen, iend, ipos
1442 : logical :: num_mr_found
1443 : character(len=*), parameter :: routine = 'parse_mode_defs'
1444 1536 : character(len=len(nl_in(1))) :: tmpstr
1445 : character(len=1) :: tmp_src_a
1446 : character(len=32) :: tmp_name_a
1447 : character(len=1) :: tmp_src_c
1448 : character(len=32) :: tmp_name_c
1449 : character(len=32) :: tmp_type
1450 : !-------------------------------------------------------------------------
1451 :
1452 : ! Determine number of modes defined by counting number of strings that are
1453 : ! terminated by ':='
1454 : ! (algorithm stops counting at first blank element).
1455 1536 : nmodes = 0
1456 1536 : nstr = 0
1457 1536 : do m = 1, n_mode_str
1458 :
1459 1536 : if (len_trim(nl_in(m)) == 0) exit
1460 0 : nstr = nstr + 1
1461 :
1462 : ! There are no fields in the input strings in which a blank character is allowed.
1463 : ! To simplify the parsing go through the input strings and remove blanks.
1464 0 : tmpstr = adjustl(nl_in(m))
1465 0 : nl_in(m) = tmpstr
1466 : do
1467 0 : strlen = len_trim(nl_in(m))
1468 0 : ipos = index(nl_in(m), ' ')
1469 0 : if (ipos == 0 .or. ipos > strlen) exit
1470 0 : tmpstr = nl_in(m)(:ipos-1) // nl_in(m)(ipos+1:strlen)
1471 0 : nl_in(m) = tmpstr
1472 : end do
1473 : ! count strings with ':=' terminator
1474 1536 : if (nl_in(m)(strlen-1:strlen) == ':=') nmodes = nmodes + 1
1475 :
1476 : end do
1477 1536 : modes%nmodes = nmodes
1478 :
1479 : ! return if no modes defined
1480 1536 : if (nmodes == 0) return
1481 :
1482 : ! allocate components that depend on nmodes
1483 : allocate( &
1484 : modes%names(nmodes), &
1485 : modes%types(nmodes), &
1486 : modes%comps(nmodes), &
1487 0 : stat=istat )
1488 0 : if (istat > 0) then
1489 0 : write(iulog,*) routine//': ERROR: cannot allocate storage for modes. nmodes=', nmodes
1490 0 : call endrun(routine//': ERROR allocating storage for modes')
1491 : end if
1492 :
1493 :
1494 0 : mcur = 1 ! index of current string being processed
1495 :
1496 : ! loop over modes
1497 0 : do m = 1, nmodes
1498 :
1499 0 : mbeg = mcur ! remember the first string of a mode
1500 :
1501 : ! check that first string in mode definition is ':=' terminated
1502 0 : iend = len_trim(nl_in(mcur))
1503 0 : if (nl_in(mcur)(iend-1:iend) /= ':=') call parse_error('= not found', nl_in(mcur))
1504 :
1505 : ! count species in mode definition. definition will contain 1 string with
1506 : ! with a ':+' terminator for each specie
1507 0 : nspec = 0
1508 0 : mcur = mcur + 1
1509 0 : do
1510 0 : iend = len_trim(nl_in(mcur))
1511 0 : if (nl_in(mcur)(iend-1:iend) /= ':+') exit
1512 0 : nspec = nspec + 1
1513 0 : mcur = mcur + 1
1514 : end do
1515 :
1516 : ! a mode must have at least one specie
1517 0 : if (nspec == 0) call parse_error('mode must have at least one specie', nl_in(mbeg))
1518 :
1519 : ! allocate components that depend on number of species
1520 : allocate( &
1521 0 : modes%comps(m)%source_mmr_a(nspec), &
1522 0 : modes%comps(m)%camname_mmr_a(nspec), &
1523 0 : modes%comps(m)%source_mmr_c(nspec), &
1524 0 : modes%comps(m)%camname_mmr_c(nspec), &
1525 0 : modes%comps(m)%type(nspec), &
1526 0 : modes%comps(m)%props(nspec), &
1527 0 : stat=istat)
1528 :
1529 0 : if (istat > 0) then
1530 0 : write(iulog,*) routine//': ERROR: cannot allocate storage for species. nspec=', nspec
1531 0 : call endrun(routine//': ERROR allocating storage for species')
1532 : end if
1533 :
1534 : ! initialize components
1535 0 : modes%comps(m)%nspec = nspec
1536 0 : modes%comps(m)%source_num_a = ' '
1537 0 : modes%comps(m)%camname_num_a = ' '
1538 0 : modes%comps(m)%source_num_c = ' '
1539 0 : modes%comps(m)%camname_num_c = ' '
1540 0 : do ispec = 1, nspec
1541 0 : modes%comps(m)%source_mmr_a(ispec) = ' '
1542 0 : modes%comps(m)%camname_mmr_a(ispec) = ' '
1543 0 : modes%comps(m)%source_mmr_c(ispec) = ' '
1544 0 : modes%comps(m)%camname_mmr_c(ispec) = ' '
1545 0 : modes%comps(m)%type(ispec) = ' '
1546 0 : modes%comps(m)%props(ispec) = ' '
1547 : end do
1548 :
1549 : ! return to first string in mode definition
1550 0 : mcur = mbeg
1551 0 : tmpstr = nl_in(mcur)
1552 :
1553 : ! mode name
1554 0 : ipos = index(tmpstr, ':')
1555 0 : if (ipos < 2) call parse_error('mode name not found', tmpstr)
1556 0 : modes%names(m) = tmpstr(:ipos-1)
1557 0 : tmpstr = tmpstr(ipos+1:)
1558 :
1559 : ! mode type
1560 0 : ipos = index(tmpstr, ':')
1561 0 : if (ipos == 0) call parse_error('mode type not found', tmpstr)
1562 : ! check for valid mode type
1563 0 : call check_mode_type(tmpstr, 1, ipos-1)
1564 0 : modes%types(m) = tmpstr(:ipos-1)
1565 0 : tmpstr = tmpstr(ipos+1:)
1566 :
1567 : ! mode type must be followed by '='
1568 0 : if (tmpstr(1:1) /= '=') call parse_error('= not found', tmpstr)
1569 :
1570 : ! move to next string
1571 0 : mcur = mcur + 1
1572 0 : tmpstr = nl_in(mcur)
1573 :
1574 : ! process mode component strings
1575 : num_mr_found = .false. ! keep track of whether number mixing ratio component is found
1576 : ispec = 0 ! keep track of the number of species found
1577 : do
1578 :
1579 : ! source of interstitial component
1580 0 : ipos = index(tmpstr, ':')
1581 0 : if (ipos < 2) call parse_error('expect to find source field first', tmpstr)
1582 : ! check for valid source
1583 0 : if (tmpstr(:ipos-1) /= 'A' .and. tmpstr(:ipos-1) /= 'N' .and. tmpstr(:ipos-1) /= 'Z') &
1584 0 : call parse_error('source must be A, N or Z', tmpstr)
1585 0 : tmp_src_a = tmpstr(:ipos-1)
1586 0 : tmpstr = tmpstr(ipos+1:)
1587 :
1588 : ! name of interstitial component
1589 0 : ipos = index(tmpstr, ':')
1590 0 : if (ipos == 0) call parse_error('next separator not found', tmpstr)
1591 0 : tmp_name_a = tmpstr(:ipos-1)
1592 0 : tmpstr = tmpstr(ipos+1:)
1593 :
1594 : ! source of cloud borne component
1595 0 : ipos = index(tmpstr, ':')
1596 0 : if (ipos < 2) call parse_error('expect to find a source field', tmpstr)
1597 : ! check for valid source
1598 0 : if (tmpstr(:ipos-1) /= 'A' .and. tmpstr(:ipos-1) /= 'N' .and. tmpstr(:ipos-1) /= 'Z') &
1599 0 : call parse_error('source must be A, N or Z', tmpstr)
1600 0 : tmp_src_c = tmpstr(:ipos-1)
1601 0 : tmpstr = tmpstr(ipos+1:)
1602 :
1603 : ! name of cloud borne component
1604 0 : ipos = index(tmpstr, ':')
1605 0 : if (ipos == 0) call parse_error('next separator not found', tmpstr)
1606 0 : tmp_name_c = tmpstr(:ipos-1)
1607 0 : tmpstr = tmpstr(ipos+1:)
1608 :
1609 : ! component type
1610 0 : ipos = scan(tmpstr, ': ')
1611 0 : if (ipos == 0) call parse_error('next separator not found', tmpstr)
1612 :
1613 0 : if (tmpstr(:ipos-1) == 'num_mr') then
1614 :
1615 : ! there can only be one number mixing ratio component
1616 0 : if (num_mr_found) call parse_error('more than 1 number component', nl_in(mcur))
1617 :
1618 0 : num_mr_found = .true.
1619 0 : modes%comps(m)%source_num_a = tmp_src_a
1620 0 : modes%comps(m)%camname_num_a = tmp_name_a
1621 0 : modes%comps(m)%source_num_c = tmp_src_c
1622 0 : modes%comps(m)%camname_num_c = tmp_name_c
1623 0 : tmpstr = tmpstr(ipos+1:)
1624 :
1625 : else
1626 :
1627 : ! check for valid specie type
1628 0 : call check_specie_type(tmpstr, 1, ipos-1)
1629 0 : tmp_type = tmpstr(:ipos-1)
1630 0 : tmpstr = tmpstr(ipos+1:)
1631 :
1632 : ! get the properties file
1633 0 : ipos = scan(tmpstr, ': ')
1634 0 : if (ipos == 0) call parse_error('next separator not found', tmpstr)
1635 : ! check for valid filename -- must have .nc extension
1636 0 : if (tmpstr(ipos-3:ipos-1) /= '.nc') &
1637 0 : call parse_error('filename not valid', tmpstr)
1638 :
1639 0 : ispec = ispec + 1
1640 0 : modes%comps(m)%source_mmr_a(ispec) = tmp_src_a
1641 0 : modes%comps(m)%camname_mmr_a(ispec) = tmp_name_a
1642 0 : modes%comps(m)%source_mmr_c(ispec) = tmp_src_c
1643 0 : modes%comps(m)%camname_mmr_c(ispec) = tmp_name_c
1644 0 : modes%comps(m)%type(ispec) = tmp_type
1645 0 : modes%comps(m)%props(ispec) = tmpstr(:ipos-1)
1646 0 : tmpstr = tmpstr(ipos+1:)
1647 : end if
1648 :
1649 : ! check if there are more components. either the current character is
1650 : ! a ' ' which means this string is the final mode component, or the character
1651 : ! is a '+' which means there are more components
1652 0 : if (tmpstr(1:1) == ' ') exit
1653 :
1654 0 : if (tmpstr(1:1) /= '+') &
1655 0 : call parse_error('+ field not found', tmpstr)
1656 :
1657 : ! continue to next component...
1658 0 : mcur = mcur + 1
1659 0 : tmpstr = nl_in(mcur)
1660 : end do
1661 :
1662 : ! check that a number component was found
1663 0 : if (.not. num_mr_found) call parse_error('number component not found', nl_in(mbeg))
1664 :
1665 : ! check that the right number of species were found
1666 0 : if (ispec /= nspec) call parse_error('component parsing got wrong number of species', nl_in(mbeg))
1667 :
1668 : ! continue to next mode...
1669 0 : mcur = mcur + 1
1670 0 : tmpstr = nl_in(mcur)
1671 : end do
1672 :
1673 : !------------------------------------------------------------------------------------------------
1674 : contains
1675 : !------------------------------------------------------------------------------------------------
1676 :
1677 : ! internal subroutines used for error checking and reporting
1678 :
1679 0 : subroutine parse_error(msg, str)
1680 :
1681 : character(len=*), intent(in) :: msg
1682 : character(len=*), intent(in) :: str
1683 :
1684 0 : write(iulog,*) routine//': ERROR: '//msg
1685 0 : write(iulog,*) ' input string: '//trim(str)
1686 0 : call endrun(routine//': ERROR: '//msg)
1687 :
1688 0 : end subroutine parse_error
1689 :
1690 : !------------------------------------------------------------------------------------------------
1691 :
1692 0 : subroutine check_specie_type(str, ib, ie)
1693 :
1694 : character(len=*), intent(in) :: str
1695 : integer, intent(in) :: ib, ie
1696 :
1697 : integer :: i
1698 :
1699 0 : do i = 1, num_spec_types
1700 0 : if (str(ib:ie) == trim(spec_type_names(i))) return
1701 : end do
1702 :
1703 0 : call parse_error('specie type not valid', str(ib:ie))
1704 :
1705 : end subroutine check_specie_type
1706 :
1707 : !------------------------------------------------------------------------------------------------
1708 :
1709 0 : subroutine check_mode_type(str, ib, ie)
1710 :
1711 : character(len=*), intent(in) :: str
1712 : integer, intent(in) :: ib, ie ! begin, end character of mode type substring
1713 :
1714 : integer :: i
1715 :
1716 0 : do i = 1, num_mode_types
1717 0 : if (str(ib:ie) == trim(mode_type_names(i))) return
1718 : end do
1719 :
1720 0 : call parse_error('mode type not valid', str(ib:ie))
1721 :
1722 : end subroutine check_mode_type
1723 :
1724 : !------------------------------------------------------------------------------------------------
1725 :
1726 : end subroutine parse_mode_defs
1727 :
1728 : !================================================================================================
1729 :
1730 16896 : subroutine parse_rad_specifier(specifier, namelist_data)
1731 :
1732 : !-----------------------------------------------------------------------------
1733 : ! Private method for parsing the radiation namelist specifiers. The specifiers
1734 : ! are of the form 'source_camname:radname' where:
1735 : ! source -- either 'N' for pbuf (non-advected) or 'A' for state (advected)
1736 : ! camname -- the name of a constituent that must be found in the constituent
1737 : ! component of the state when source=A or in the physics buffer
1738 : ! when source=N
1739 : ! radname -- For gases this is a name that identifies the constituent to the
1740 : ! radiative transfer codes. These names are contained in the
1741 : ! radconstants module. For aerosols this is a filename, which is
1742 : ! identified by a ".nc" suffix. The file contains optical and
1743 : ! other physical properties of the aerosol.
1744 : !
1745 : ! This code also identifies whether the constituent is a gas or an aerosol
1746 : ! and adds that info to a structure that stores the parsed data.
1747 : !-----------------------------------------------------------------------------
1748 :
1749 : character(len=*), dimension(:), intent(in) :: specifier
1750 : type(rad_cnst_namelist_t), intent(inout) :: namelist_data
1751 :
1752 : ! Local variables
1753 : integer :: number, i, j
1754 : integer :: ipos, strlen
1755 : integer :: astat
1756 : character(len=cs1) :: tmpstr
1757 : character(len=1) :: source(n_rad_cnst)
1758 : character(len=64) :: camname(n_rad_cnst)
1759 : character(len=cs1) :: radname(n_rad_cnst)
1760 : character(len=1) :: type(n_rad_cnst)
1761 : !-------------------------------------------------------------------------
1762 :
1763 16896 : number = 0
1764 :
1765 29184 : parse_loop: do i = 1, n_rad_cnst
1766 29184 : if ( len_trim(specifier(i)) == 0 ) then
1767 : exit parse_loop
1768 : endif
1769 :
1770 : ! There are no fields in the input strings in which a blank character is allowed.
1771 : ! To simplify the parsing go through the input strings and remove blanks.
1772 12288 : tmpstr = adjustl(specifier(i))
1773 0 : do
1774 12288 : strlen = len_trim(tmpstr)
1775 12288 : ipos = index(tmpstr, ' ')
1776 12288 : if (ipos == 0 .or. ipos > strlen) exit
1777 12288 : tmpstr = tmpstr(:ipos-1) // tmpstr(ipos+1:strlen)
1778 : end do
1779 :
1780 : ! Locate the ':' separating source from camname.
1781 12288 : j = index(tmpstr, ':')
1782 12288 : source(i) = tmpstr(:j-1)
1783 12288 : tmpstr = tmpstr(j+1:)
1784 :
1785 : ! locate the ':' separating camname from radname
1786 12288 : j = scan(tmpstr, ':')
1787 :
1788 12288 : camname(i) = tmpstr(:j-1)
1789 12288 : radname(i) = tmpstr(j+1:)
1790 :
1791 : ! determine the type of constituent
1792 12288 : if (source(i) == 'M') then
1793 0 : type(i) = 'M'
1794 12288 : else if(index(radname(i),".nc") .gt. 0) then
1795 0 : type(i) = 'A'
1796 : else
1797 12288 : type(i) = 'G'
1798 : end if
1799 :
1800 29184 : number = number+1
1801 : end do parse_loop
1802 :
1803 16896 : namelist_data%ncnst = number
1804 :
1805 16896 : if (number == 0) return
1806 :
1807 3072 : allocate(namelist_data%source (number), stat=astat)
1808 1536 : if( astat/= 0 ) call endrun('parse_rad_specifier: not able to allocate namelist_data%source')
1809 4608 : allocate(namelist_data%camname(number), stat=astat)
1810 0 : if( astat/= 0 ) call endrun('parse_rad_specifier: not able to allocate namelist_data%camname')
1811 4608 : allocate(namelist_data%radname(number), stat=astat)
1812 0 : if( astat/= 0 ) call endrun('parse_rad_specifier: not able to allocate namelist_data%radname')
1813 3072 : allocate(namelist_data%type(number), stat=astat)
1814 0 : if( astat/= 0 ) call endrun('parse_rad_specifier: not able to allocate namelist_data%type')
1815 :
1816 13824 : namelist_data%source(:namelist_data%ncnst) = source (:namelist_data%ncnst)
1817 13824 : namelist_data%camname(:namelist_data%ncnst) = camname(:namelist_data%ncnst)
1818 13824 : namelist_data%radname(:namelist_data%ncnst) = radname(:namelist_data%ncnst)
1819 13824 : namelist_data%type(:namelist_data%ncnst) = type(:namelist_data%ncnst)
1820 :
1821 : end subroutine parse_rad_specifier
1822 :
1823 : !================================================================================================
1824 :
1825 0 : subroutine rad_cnst_get_aer_mmr_by_idx(list_idx, aer_idx, state, pbuf, mmr)
1826 :
1827 : ! Return pointer to mass mixing ratio for the aerosol from the specified
1828 : ! climate or diagnostic list.
1829 :
1830 : ! Arguments
1831 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
1832 : integer, intent(in) :: aer_idx
1833 : type(physics_state), target, intent(in) :: state
1834 : type(physics_buffer_desc), pointer :: pbuf(:)
1835 : real(r8), pointer :: mmr(:,:)
1836 :
1837 : ! Local variables
1838 : integer :: lchnk
1839 : integer :: idx
1840 : character(len=1) :: source
1841 : type(aerlist_t), pointer :: aerlist
1842 : character(len=*), parameter :: subname = 'rad_cnst_get_aer_mmr_by_idx'
1843 : !-----------------------------------------------------------------------------
1844 :
1845 0 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
1846 0 : aerlist => aerosollist(list_idx)
1847 : else
1848 0 : write(iulog,*) subname//': list_idx =', list_idx
1849 0 : call endrun(subname//': list_idx out of bounds')
1850 : endif
1851 :
1852 0 : lchnk = state%lchnk
1853 :
1854 : ! Check for valid input aerosol index
1855 0 : if (aer_idx < 1 .or. aer_idx > aerlist%numaerosols) then
1856 0 : write(iulog,*) subname//': aer_idx= ', aer_idx, ' numaerosols= ', aerlist%numaerosols
1857 0 : call endrun(subname//': aerosol list index out of range')
1858 : end if
1859 :
1860 : ! Get data source
1861 0 : source = aerlist%aer(aer_idx)%source
1862 0 : idx = aerlist%aer(aer_idx)%idx
1863 0 : select case( source )
1864 : case ('A')
1865 0 : mmr => state%q(:,:,idx)
1866 : case ('N')
1867 0 : call pbuf_get_field(pbuf, idx, mmr)
1868 : case ('Z')
1869 0 : mmr => zero_cols
1870 : end select
1871 :
1872 0 : end subroutine rad_cnst_get_aer_mmr_by_idx
1873 :
1874 : !================================================================================================
1875 :
1876 0 : subroutine rad_cnst_get_mam_mmr_by_idx(list_idx, mode_idx, spec_idx, phase, state, pbuf, mmr)
1877 :
1878 : ! Return pointer to mass mixing ratio for the modal aerosol specie from the specified
1879 : ! climate or diagnostic list.
1880 :
1881 : ! Arguments
1882 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
1883 : integer, intent(in) :: mode_idx ! mode index
1884 : integer, intent(in) :: spec_idx ! index of specie in the mode
1885 : character(len=1), intent(in) :: phase ! 'a' for interstitial, 'c' for cloud borne
1886 : type(physics_state), target, intent(in) :: state
1887 : type(physics_buffer_desc), pointer :: pbuf(:)
1888 : real(r8), pointer :: mmr(:,:)
1889 :
1890 : ! Local variables
1891 : integer :: m_idx
1892 : integer :: idx
1893 : integer :: lchnk
1894 : character(len=1) :: source
1895 : type(modelist_t), pointer :: mlist
1896 : character(len=*), parameter :: subname = 'rad_cnst_get_mam_mmr_by_idx'
1897 : !-----------------------------------------------------------------------------
1898 :
1899 0 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
1900 0 : mlist => ma_list(list_idx)
1901 : else
1902 0 : write(iulog,*) subname//': list_idx =', list_idx
1903 0 : call endrun(subname//': list_idx out of bounds')
1904 : endif
1905 :
1906 : ! Check for valid mode index
1907 0 : if (mode_idx < 1 .or. mode_idx > mlist%nmodes) then
1908 0 : write(iulog,*) subname//': mode_idx= ', mode_idx, ' nmodes= ', mlist%nmodes
1909 0 : call endrun(subname//': mode list index out of range')
1910 : end if
1911 :
1912 : ! Get the index for the corresponding mode in the mode definition object
1913 0 : m_idx = mlist%idx(mode_idx)
1914 :
1915 : ! Check for valid specie index
1916 0 : if (spec_idx < 1 .or. spec_idx > modes%comps(m_idx)%nspec) then
1917 0 : write(iulog,*) subname//': spec_idx= ', spec_idx, ' nspec= ', modes%comps(m_idx)%nspec
1918 0 : call endrun(subname//': specie list index out of range')
1919 : end if
1920 :
1921 : ! Get data source
1922 0 : if (phase == 'a') then
1923 0 : source = modes%comps(m_idx)%source_mmr_a(spec_idx)
1924 0 : idx = modes%comps(m_idx)%idx_mmr_a(spec_idx)
1925 0 : else if (phase == 'c') then
1926 0 : source = modes%comps(m_idx)%source_mmr_c(spec_idx)
1927 0 : idx = modes%comps(m_idx)%idx_mmr_c(spec_idx)
1928 : else
1929 0 : write(iulog,*) subname//': phase= ', phase
1930 0 : call endrun(subname//': unrecognized phase; must be "a" or "c"')
1931 : end if
1932 :
1933 0 : lchnk = state%lchnk
1934 :
1935 0 : select case( source )
1936 : case ('A')
1937 0 : mmr => state%q(:,:,idx)
1938 : case ('N')
1939 0 : call pbuf_get_field(pbuf, idx, mmr)
1940 : case ('Z')
1941 0 : mmr => zero_cols
1942 : end select
1943 :
1944 0 : end subroutine rad_cnst_get_mam_mmr_by_idx
1945 :
1946 : !================================================================================================
1947 :
1948 0 : subroutine rad_cnst_get_mam_mmr_idx(mode_idx, spec_idx, idx)
1949 :
1950 : ! Return constituent index of mam specie mass mixing ratio for aerosol modes in
1951 : ! the climate list.
1952 :
1953 : ! This is a special routine to allow direct access to information in the
1954 : ! constituent array inside physics parameterizations that have been passed,
1955 : ! and are operating over the entire constituent array. The interstitial phase
1956 : ! is assumed since that's what is contained in the constituent array.
1957 :
1958 : ! Arguments
1959 : integer, intent(in) :: mode_idx ! mode index
1960 : integer, intent(in) :: spec_idx ! index of specie in the mode
1961 : integer, intent(out) :: idx ! index of specie in the constituent array
1962 :
1963 : ! Local variables
1964 : integer :: m_idx
1965 : type(modelist_t), pointer :: mlist
1966 : character(len=*), parameter :: subname = 'rad_cnst_get_mam_mmr_idx'
1967 : !-----------------------------------------------------------------------------
1968 :
1969 : ! assume climate list (i.e., species are in the constituent array)
1970 0 : mlist => ma_list(0)
1971 :
1972 : ! Check for valid mode index
1973 0 : if (mode_idx < 1 .or. mode_idx > mlist%nmodes) then
1974 0 : write(iulog,*) subname//': mode_idx= ', mode_idx, ' nmodes= ', mlist%nmodes
1975 0 : call endrun(subname//': mode list index out of range')
1976 : end if
1977 :
1978 : ! Get the index for the corresponding mode in the mode definition object
1979 0 : m_idx = mlist%idx(mode_idx)
1980 :
1981 : ! Check for valid specie index
1982 0 : if (spec_idx < 1 .or. spec_idx > modes%comps(m_idx)%nspec) then
1983 0 : write(iulog,*) subname//': spec_idx= ', spec_idx, ' nspec= ', modes%comps(m_idx)%nspec
1984 0 : call endrun(subname//': specie list index out of range')
1985 : end if
1986 :
1987 : ! Assume data source is interstitial since that's what's in the constituent array
1988 0 : idx = modes%comps(m_idx)%idx_mmr_a(spec_idx)
1989 :
1990 0 : end subroutine rad_cnst_get_mam_mmr_idx
1991 :
1992 : !================================================================================================
1993 :
1994 0 : subroutine rad_cnst_get_mode_num(list_idx, mode_idx, phase, state, pbuf, num)
1995 :
1996 : ! Return pointer to number mixing ratio for the aerosol mode from the specified
1997 : ! climate or diagnostic list.
1998 :
1999 : ! Arguments
2000 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
2001 : integer, intent(in) :: mode_idx ! mode index
2002 : character(len=1), intent(in) :: phase ! 'a' for interstitial, 'c' for cloud borne
2003 : type(physics_state), target, intent(in) :: state
2004 : type(physics_buffer_desc), pointer :: pbuf(:)
2005 : real(r8), pointer :: num(:,:)
2006 :
2007 : ! Local variables
2008 : integer :: m_idx
2009 : integer :: idx
2010 : integer :: lchnk
2011 : character(len=1) :: source
2012 : type(modelist_t), pointer :: mlist
2013 : character(len=*), parameter :: subname = 'rad_cnst_get_mode_num'
2014 : !-----------------------------------------------------------------------------
2015 :
2016 0 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
2017 0 : mlist => ma_list(list_idx)
2018 : else
2019 0 : write(iulog,*) subname//': list_idx =', list_idx
2020 0 : call endrun(subname//': list_idx out of bounds')
2021 : endif
2022 :
2023 : ! Check for valid mode index
2024 0 : if (mode_idx < 1 .or. mode_idx > mlist%nmodes) then
2025 0 : write(iulog,*) subname//': mode_idx= ', mode_idx, ' nmodes= ', mlist%nmodes
2026 0 : call endrun(subname//': mode list index out of range')
2027 : end if
2028 :
2029 : ! Get the index for the corresponding mode in the mode definition object
2030 0 : m_idx = mlist%idx(mode_idx)
2031 :
2032 : ! Get data source
2033 0 : if (phase == 'a') then
2034 0 : source = modes%comps(m_idx)%source_num_a
2035 0 : idx = modes%comps(m_idx)%idx_num_a
2036 0 : else if (phase == 'c') then
2037 0 : source = modes%comps(m_idx)%source_num_c
2038 0 : idx = modes%comps(m_idx)%idx_num_c
2039 : else
2040 0 : write(iulog,*) subname//': phase= ', phase
2041 0 : call endrun(subname//': unrecognized phase; must be "a" or "c"')
2042 : end if
2043 :
2044 0 : lchnk = state%lchnk
2045 :
2046 0 : select case( source )
2047 : case ('A')
2048 0 : num => state%q(:,:,idx)
2049 : case ('N')
2050 0 : call pbuf_get_field(pbuf, idx, num)
2051 : case ('Z')
2052 0 : num => zero_cols
2053 : end select
2054 :
2055 0 : end subroutine rad_cnst_get_mode_num
2056 :
2057 : !================================================================================================
2058 :
2059 0 : subroutine rad_cnst_get_mode_num_idx(mode_idx, cnst_idx)
2060 :
2061 : ! Return constituent index of mode number mixing ratio for the aerosol mode in
2062 : ! the climate list.
2063 :
2064 : ! This is a special routine to allow direct access to information in the
2065 : ! constituent array inside physics parameterizations that have been passed,
2066 : ! and are operating over the entire constituent array. The interstitial phase
2067 : ! is assumed since that's what is contained in the constituent array.
2068 :
2069 : ! Arguments
2070 : integer, intent(in) :: mode_idx ! mode index
2071 : integer, intent(out) :: cnst_idx ! constituent index
2072 :
2073 : ! Local variables
2074 : integer :: m_idx
2075 : character(len=1) :: source
2076 : type(modelist_t), pointer :: mlist
2077 : character(len=*), parameter :: subname = 'rad_cnst_get_mode_num'
2078 : !-----------------------------------------------------------------------------
2079 :
2080 : ! assume climate list
2081 0 : mlist => ma_list(0)
2082 :
2083 : ! Check for valid mode index
2084 0 : if (mode_idx < 1 .or. mode_idx > mlist%nmodes) then
2085 0 : write(iulog,*) subname//': mode_idx= ', mode_idx, ' nmodes= ', mlist%nmodes
2086 0 : call endrun(subname//': mode list index out of range')
2087 : end if
2088 :
2089 : ! Get the index for the corresponding mode in the mode definition object
2090 0 : m_idx = mlist%idx(mode_idx)
2091 :
2092 : ! Check that source is 'A' which means the index is for the constituent array
2093 0 : source = modes%comps(m_idx)%source_num_a
2094 0 : if (source /= 'A') then
2095 0 : write(iulog,*) subname//': source= ', source
2096 0 : call endrun(subname//': requested mode number index not in constituent array')
2097 : end if
2098 :
2099 : ! Return index in constituent array
2100 0 : cnst_idx = modes%comps(m_idx)%idx_num_a
2101 :
2102 0 : end subroutine rad_cnst_get_mode_num_idx
2103 :
2104 : !================================================================================================
2105 :
2106 : integer function rad_cnst_get_aer_idx(list_idx, aer_name)
2107 :
2108 : ! Return the index of aerosol aer_name in the list specified by list_idx.
2109 :
2110 : ! Arguments
2111 : integer, intent(in) :: list_idx ! 0 for climate list, 1-N_DIAG for diagnostic lists
2112 : character(len=*), intent(in) :: aer_name ! aerosol name (in state or pbuf)
2113 :
2114 : ! Local variables
2115 : integer :: i, aer_idx
2116 : type(aerlist_t), pointer :: aerlist
2117 : character(len=*), parameter :: subname = "rad_cnst_get_aer_idx"
2118 : !-------------------------------------------------------------------------
2119 :
2120 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
2121 : aerlist => aerosollist(list_idx)
2122 : else
2123 : write(iulog,*) subname//': list_idx =', list_idx
2124 : call endrun(subname//': list_idx out of bounds')
2125 : endif
2126 :
2127 : ! Get index in aerosol list for requested name
2128 : aer_idx = -1
2129 : do i = 1, aerlist%numaerosols
2130 : if (trim(aer_name) == trim(aerlist%aer(i)%camname)) then
2131 : aer_idx = i
2132 : exit
2133 : end if
2134 : end do
2135 :
2136 : if (aer_idx == -1) call endrun(subname//": ERROR - name not found")
2137 :
2138 : rad_cnst_get_aer_idx = aer_idx
2139 :
2140 : end function rad_cnst_get_aer_idx
2141 :
2142 : !================================================================================================
2143 :
2144 0 : subroutine rad_cnst_get_aer_props_by_idx(list_idx, &
2145 0 : aer_idx, opticstype, &
2146 : sw_hygro_ext, sw_hygro_ssa, sw_hygro_asm, lw_hygro_ext, &
2147 : sw_nonhygro_ext, sw_nonhygro_ssa, sw_nonhygro_asm, &
2148 : sw_nonhygro_scat, sw_nonhygro_ascat, lw_ext, &
2149 : refindex_aer_sw, refindex_aer_lw, &
2150 : r_sw_ext, r_sw_scat, r_sw_ascat, r_lw_abs, mu, &
2151 0 : aername, density_aer, hygro_aer, dryrad_aer, dispersion_aer, num_to_mass_aer)
2152 :
2153 : ! Return requested properties for the aerosol from the specified
2154 : ! climate or diagnostic list.
2155 :
2156 : use phys_prop, only: physprop_get
2157 :
2158 :
2159 : ! Arguments
2160 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
2161 : integer, intent(in) :: aer_idx ! index of the aerosol
2162 : character(len=ot_length), optional, intent(out) :: opticstype
2163 : real(r8), optional, pointer :: sw_hygro_ext(:,:)
2164 : real(r8), optional, pointer :: sw_hygro_ssa(:,:)
2165 : real(r8), optional, pointer :: sw_hygro_asm(:,:)
2166 : real(r8), optional, pointer :: lw_hygro_ext(:,:)
2167 : real(r8), optional, pointer :: sw_nonhygro_ext(:)
2168 : real(r8), optional, pointer :: sw_nonhygro_ssa(:)
2169 : real(r8), optional, pointer :: sw_nonhygro_asm(:)
2170 : real(r8), optional, pointer :: sw_nonhygro_scat(:)
2171 : real(r8), optional, pointer :: sw_nonhygro_ascat(:)
2172 : real(r8), optional, pointer :: lw_ext(:)
2173 : complex(r8), optional, pointer :: refindex_aer_sw(:)
2174 : complex(r8), optional, pointer :: refindex_aer_lw(:)
2175 : character(len=20), optional, intent(out) :: aername
2176 : real(r8), optional, intent(out) :: density_aer
2177 : real(r8), optional, intent(out) :: hygro_aer
2178 : real(r8), optional, intent(out) :: dryrad_aer
2179 : real(r8), optional, intent(out) :: dispersion_aer
2180 : real(r8), optional, intent(out) :: num_to_mass_aer
2181 :
2182 : real(r8), optional, pointer :: r_sw_ext(:,:)
2183 : real(r8), optional, pointer :: r_sw_scat(:,:)
2184 : real(r8), optional, pointer :: r_sw_ascat(:,:)
2185 : real(r8), optional, pointer :: r_lw_abs(:,:)
2186 : real(r8), optional, pointer :: mu(:)
2187 :
2188 : ! Local variables
2189 : integer :: id
2190 : character(len=*), parameter :: subname = 'rad_cnst_get_aer_props_by_idx'
2191 : type(aerlist_t), pointer :: aerlist
2192 : !------------------------------------------------------------------------------------
2193 :
2194 0 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
2195 0 : aerlist => aerosollist(list_idx)
2196 : else
2197 0 : write(iulog,*) subname//': list_idx = ', list_idx
2198 0 : call endrun(subname//': list_idx out of range')
2199 : endif
2200 :
2201 0 : if (aer_idx < 1 .or. aer_idx > aerlist%numaerosols) then
2202 0 : write(iulog,*) subname//': aerosol list index out of range: ', aer_idx ,' list index: ',list_idx
2203 0 : call endrun(subname//': aer_idx out of range')
2204 : end if
2205 :
2206 0 : id = aerlist%aer(aer_idx)%physprop_id
2207 :
2208 0 : if (present(opticstype)) call physprop_get(id, opticstype=opticstype)
2209 :
2210 0 : if (present(sw_hygro_ext)) call physprop_get(id, sw_hygro_ext=sw_hygro_ext)
2211 0 : if (present(sw_hygro_ssa)) call physprop_get(id, sw_hygro_ssa=sw_hygro_ssa)
2212 0 : if (present(sw_hygro_asm)) call physprop_get(id, sw_hygro_asm=sw_hygro_asm)
2213 0 : if (present(lw_hygro_ext)) call physprop_get(id, lw_hygro_abs=lw_hygro_ext)
2214 :
2215 0 : if (present(sw_nonhygro_ext)) call physprop_get(id, sw_nonhygro_ext=sw_nonhygro_ext)
2216 0 : if (present(sw_nonhygro_ssa)) call physprop_get(id, sw_nonhygro_ssa=sw_nonhygro_ssa)
2217 0 : if (present(sw_nonhygro_asm)) call physprop_get(id, sw_nonhygro_asm=sw_nonhygro_asm)
2218 0 : if (present(sw_nonhygro_scat)) call physprop_get(id, sw_nonhygro_scat=sw_nonhygro_scat)
2219 0 : if (present(sw_nonhygro_ascat)) call physprop_get(id, sw_nonhygro_ascat=sw_nonhygro_ascat)
2220 0 : if (present(lw_ext)) call physprop_get(id, lw_abs=lw_ext)
2221 :
2222 0 : if (present(refindex_aer_sw)) call physprop_get(id, refindex_aer_sw=refindex_aer_sw)
2223 0 : if (present(refindex_aer_lw)) call physprop_get(id, refindex_aer_lw=refindex_aer_lw)
2224 :
2225 0 : if (present(aername)) call physprop_get(id, aername=aername)
2226 0 : if (present(density_aer)) call physprop_get(id, density_aer=density_aer)
2227 0 : if (present(hygro_aer)) call physprop_get(id, hygro_aer=hygro_aer)
2228 0 : if (present(dryrad_aer)) call physprop_get(id, dryrad_aer=dryrad_aer)
2229 0 : if (present(dispersion_aer)) call physprop_get(id, dispersion_aer=dispersion_aer)
2230 0 : if (present(num_to_mass_aer)) call physprop_get(id, num_to_mass_aer=num_to_mass_aer)
2231 :
2232 0 : if (present(r_lw_abs)) call physprop_get(id, r_lw_abs=r_lw_abs)
2233 0 : if (present(r_sw_ext)) call physprop_get(id, r_sw_ext=r_sw_ext)
2234 0 : if (present(r_sw_scat)) call physprop_get(id, r_sw_scat=r_sw_scat)
2235 0 : if (present(r_sw_ascat)) call physprop_get(id, r_sw_ascat=r_sw_ascat)
2236 0 : if (present(mu)) call physprop_get(id, mu=mu)
2237 :
2238 0 : end subroutine rad_cnst_get_aer_props_by_idx
2239 :
2240 : !================================================================================================
2241 :
2242 0 : subroutine rad_cnst_get_mam_props_by_idx(list_idx, &
2243 0 : mode_idx, spec_idx, opticstype, &
2244 : sw_hygro_ext, sw_hygro_ssa, sw_hygro_asm, lw_hygro_ext, &
2245 : sw_nonhygro_ext, sw_nonhygro_ssa, sw_nonhygro_asm, &
2246 : sw_nonhygro_scat, sw_nonhygro_ascat, lw_ext, &
2247 : refindex_aer_sw, refindex_aer_lw, &
2248 : r_sw_ext, r_sw_scat, r_sw_ascat, r_lw_abs, mu, &
2249 0 : aername, density_aer, hygro_aer, dryrad_aer, dispersion_aer, &
2250 0 : num_to_mass_aer, spectype)
2251 :
2252 : ! Return requested properties for the aerosol from the specified
2253 : ! climate or diagnostic list.
2254 :
2255 0 : use phys_prop, only: physprop_get
2256 :
2257 : ! Arguments
2258 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
2259 : integer, intent(in) :: mode_idx ! mode index
2260 : integer, intent(in) :: spec_idx ! index of specie in the mode
2261 : character(len=ot_length), optional, intent(out) :: opticstype
2262 : real(r8), optional, pointer :: sw_hygro_ext(:,:)
2263 : real(r8), optional, pointer :: sw_hygro_ssa(:,:)
2264 : real(r8), optional, pointer :: sw_hygro_asm(:,:)
2265 : real(r8), optional, pointer :: lw_hygro_ext(:,:)
2266 : real(r8), optional, pointer :: sw_nonhygro_ext(:)
2267 : real(r8), optional, pointer :: sw_nonhygro_ssa(:)
2268 : real(r8), optional, pointer :: sw_nonhygro_asm(:)
2269 : real(r8), optional, pointer :: sw_nonhygro_scat(:)
2270 : real(r8), optional, pointer :: sw_nonhygro_ascat(:)
2271 : real(r8), optional, pointer :: lw_ext(:)
2272 : complex(r8), optional, pointer :: refindex_aer_sw(:)
2273 : complex(r8), optional, pointer :: refindex_aer_lw(:)
2274 :
2275 : real(r8), optional, pointer :: r_sw_ext(:,:)
2276 : real(r8), optional, pointer :: r_sw_scat(:,:)
2277 : real(r8), optional, pointer :: r_sw_ascat(:,:)
2278 : real(r8), optional, pointer :: r_lw_abs(:,:)
2279 : real(r8), optional, pointer :: mu(:)
2280 :
2281 : character(len=20), optional, intent(out) :: aername
2282 : real(r8), optional, intent(out) :: density_aer
2283 : real(r8), optional, intent(out) :: hygro_aer
2284 : real(r8), optional, intent(out) :: dryrad_aer
2285 : real(r8), optional, intent(out) :: dispersion_aer
2286 : real(r8), optional, intent(out) :: num_to_mass_aer
2287 : character(len=32), optional, intent(out) :: spectype
2288 :
2289 : ! Local variables
2290 : integer :: m_idx, id
2291 : type(modelist_t), pointer :: mlist
2292 : character(len=*), parameter :: subname = 'rad_cnst_get_mam_props_by_idx'
2293 : !------------------------------------------------------------------------------------
2294 :
2295 0 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
2296 0 : mlist => ma_list(list_idx)
2297 : else
2298 0 : write(iulog,*) subname//': list_idx = ', list_idx
2299 0 : call endrun(subname//': list_idx out of range')
2300 : endif
2301 :
2302 : ! Check for valid mode index
2303 0 : if (mode_idx < 1 .or. mode_idx > mlist%nmodes) then
2304 0 : write(iulog,*) subname//': mode_idx= ', mode_idx, ' nmodes= ', mlist%nmodes
2305 0 : call endrun(subname//': mode list index out of range')
2306 : end if
2307 :
2308 : ! Get the index for the corresponding mode in the mode definition object
2309 0 : m_idx = mlist%idx(mode_idx)
2310 :
2311 : ! Check for valid specie index
2312 0 : if (spec_idx < 1 .or. spec_idx > modes%comps(m_idx)%nspec) then
2313 0 : write(iulog,*) subname//': spec_idx= ', spec_idx, ' nspec= ', modes%comps(m_idx)%nspec
2314 0 : call endrun(subname//': specie list index out of range')
2315 : end if
2316 :
2317 0 : id = modes%comps(m_idx)%idx_props(spec_idx)
2318 :
2319 0 : if (present(opticstype)) call physprop_get(id, opticstype=opticstype)
2320 :
2321 0 : if (present(sw_hygro_ext)) call physprop_get(id, sw_hygro_ext=sw_hygro_ext)
2322 0 : if (present(sw_hygro_ssa)) call physprop_get(id, sw_hygro_ssa=sw_hygro_ssa)
2323 0 : if (present(sw_hygro_asm)) call physprop_get(id, sw_hygro_asm=sw_hygro_asm)
2324 0 : if (present(lw_hygro_ext)) call physprop_get(id, lw_hygro_abs=lw_hygro_ext)
2325 :
2326 0 : if (present(sw_nonhygro_ext)) call physprop_get(id, sw_nonhygro_ext=sw_nonhygro_ext)
2327 0 : if (present(sw_nonhygro_ssa)) call physprop_get(id, sw_nonhygro_ssa=sw_nonhygro_ssa)
2328 0 : if (present(sw_nonhygro_asm)) call physprop_get(id, sw_nonhygro_asm=sw_nonhygro_asm)
2329 0 : if (present(sw_nonhygro_scat)) call physprop_get(id, sw_nonhygro_scat=sw_nonhygro_scat)
2330 0 : if (present(sw_nonhygro_ascat)) call physprop_get(id, sw_nonhygro_ascat=sw_nonhygro_ascat)
2331 0 : if (present(lw_ext)) call physprop_get(id, lw_abs=lw_ext)
2332 :
2333 0 : if (present(refindex_aer_sw)) call physprop_get(id, refindex_aer_sw=refindex_aer_sw)
2334 0 : if (present(refindex_aer_lw)) call physprop_get(id, refindex_aer_lw=refindex_aer_lw)
2335 :
2336 0 : if (present(r_lw_abs)) call physprop_get(id, r_lw_abs=r_lw_abs)
2337 0 : if (present(r_sw_ext)) call physprop_get(id, r_sw_ext=r_sw_ext)
2338 0 : if (present(r_sw_scat)) call physprop_get(id, r_sw_scat=r_sw_scat)
2339 0 : if (present(r_sw_ascat)) call physprop_get(id, r_sw_ascat=r_sw_ascat)
2340 0 : if (present(mu)) call physprop_get(id, mu=mu)
2341 :
2342 0 : if (present(aername)) call physprop_get(id, aername=aername)
2343 0 : if (present(density_aer)) call physprop_get(id, density_aer=density_aer)
2344 0 : if (present(hygro_aer)) call physprop_get(id, hygro_aer=hygro_aer)
2345 0 : if (present(dryrad_aer)) call physprop_get(id, dryrad_aer=dryrad_aer)
2346 0 : if (present(dispersion_aer)) call physprop_get(id, dispersion_aer=dispersion_aer)
2347 0 : if (present(num_to_mass_aer)) call physprop_get(id, num_to_mass_aer=num_to_mass_aer)
2348 :
2349 0 : if (present(spectype)) spectype = modes%comps(m_idx)%type(spec_idx)
2350 :
2351 0 : end subroutine rad_cnst_get_mam_props_by_idx
2352 :
2353 : !================================================================================================
2354 :
2355 0 : subroutine rad_cnst_get_mode_props(list_idx, mode_idx, opticstype, &
2356 : extpsw, abspsw, asmpsw, absplw, refrtabsw, &
2357 : refitabsw, refrtablw, refitablw, ncoef, prefr, &
2358 : prefi, sigmag, dgnum, dgnumlo, dgnumhi, &
2359 : rhcrystal, rhdeliques)
2360 :
2361 : ! Return requested properties for the mode from the specified
2362 : ! climate or diagnostic list.
2363 :
2364 0 : use phys_prop, only: physprop_get
2365 :
2366 : ! Arguments
2367 : integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
2368 : integer, intent(in) :: mode_idx ! mode index
2369 : character(len=ot_length), optional, intent(out) :: opticstype
2370 : real(r8), optional, pointer :: extpsw(:,:,:,:)
2371 : real(r8), optional, pointer :: abspsw(:,:,:,:)
2372 : real(r8), optional, pointer :: asmpsw(:,:,:,:)
2373 : real(r8), optional, pointer :: absplw(:,:,:,:)
2374 : real(r8), optional, pointer :: refrtabsw(:,:)
2375 : real(r8), optional, pointer :: refitabsw(:,:)
2376 : real(r8), optional, pointer :: refrtablw(:,:)
2377 : real(r8), optional, pointer :: refitablw(:,:)
2378 : integer, optional, intent(out) :: ncoef
2379 : integer, optional, intent(out) :: prefr
2380 : integer, optional, intent(out) :: prefi
2381 : real(r8), optional, intent(out) :: sigmag
2382 : real(r8), optional, intent(out) :: dgnum
2383 : real(r8), optional, intent(out) :: dgnumlo
2384 : real(r8), optional, intent(out) :: dgnumhi
2385 : real(r8), optional, intent(out) :: rhcrystal
2386 : real(r8), optional, intent(out) :: rhdeliques
2387 :
2388 : ! Local variables
2389 : integer :: id
2390 : type(modelist_t), pointer :: mlist
2391 : character(len=*), parameter :: subname = 'rad_cnst_get_mode_props'
2392 : !------------------------------------------------------------------------------------
2393 :
2394 0 : if (list_idx >= 0 .and. list_idx <= N_DIAG) then
2395 0 : mlist => ma_list(list_idx)
2396 : else
2397 0 : write(iulog,*) subname//': list_idx = ', list_idx
2398 0 : call endrun(subname//': list_idx out of range')
2399 : endif
2400 :
2401 : ! Check for valid mode index
2402 0 : if (mode_idx < 1 .or. mode_idx > mlist%nmodes) then
2403 0 : write(iulog,*) subname//': mode_idx= ', mode_idx, ' nmodes= ', mlist%nmodes
2404 0 : call endrun(subname//': mode list index out of range')
2405 : end if
2406 :
2407 : ! Get the physprop index for the requested mode
2408 0 : id = mlist%idx_props(mode_idx)
2409 :
2410 0 : if (present(opticstype)) call physprop_get(id, opticstype=opticstype)
2411 0 : if (present(extpsw)) call physprop_get(id, extpsw=extpsw)
2412 0 : if (present(abspsw)) call physprop_get(id, abspsw=abspsw)
2413 0 : if (present(asmpsw)) call physprop_get(id, asmpsw=asmpsw)
2414 0 : if (present(absplw)) call physprop_get(id, absplw=absplw)
2415 :
2416 0 : if (present(refrtabsw)) call physprop_get(id, refrtabsw=refrtabsw)
2417 0 : if (present(refitabsw)) call physprop_get(id, refitabsw=refitabsw)
2418 0 : if (present(refrtablw)) call physprop_get(id, refrtablw=refrtablw)
2419 0 : if (present(refitablw)) call physprop_get(id, refitablw=refitablw)
2420 :
2421 0 : if (present(ncoef)) call physprop_get(id, ncoef=ncoef)
2422 0 : if (present(prefr)) call physprop_get(id, prefr=prefr)
2423 0 : if (present(prefi)) call physprop_get(id, prefi=prefi)
2424 0 : if (present(sigmag)) call physprop_get(id, sigmag=sigmag)
2425 0 : if (present(dgnum)) call physprop_get(id, dgnum=dgnum)
2426 0 : if (present(dgnumlo)) call physprop_get(id, dgnumlo=dgnumlo)
2427 0 : if (present(dgnumhi)) call physprop_get(id, dgnumhi=dgnumhi)
2428 0 : if (present(rhcrystal)) call physprop_get(id, rhcrystal=rhcrystal)
2429 0 : if (present(rhdeliques)) call physprop_get(id, rhdeliques=rhdeliques)
2430 :
2431 0 : end subroutine rad_cnst_get_mode_props
2432 :
2433 : !================================================================================================
2434 :
2435 2 : subroutine print_modes(modes)
2436 :
2437 : type(modes_t), intent(inout) :: modes
2438 :
2439 : integer :: i, m
2440 : !---------------------------------------------------------------------------------------------
2441 :
2442 2 : write(iulog,*)' Mode Definitions'
2443 :
2444 2 : do m = 1, modes%nmodes
2445 :
2446 0 : write(iulog,*) nl//' name=',trim(modes%names(m)),' type=',trim(modes%types(m))
2447 0 : write(iulog,*) ' src_a=',trim(modes%comps(m)%source_num_a),' num_a=',trim(modes%comps(m)%camname_num_a), &
2448 0 : ' src_c=',trim(modes%comps(m)%source_num_c),' num_c=',trim(modes%comps(m)%camname_num_c)
2449 :
2450 2 : do i = 1, modes%comps(m)%nspec
2451 :
2452 0 : write(iulog,*) ' src_a=',trim(modes%comps(m)%source_mmr_a(i)), ' mmr_a=',trim(modes%comps(m)%camname_mmr_a(i)), &
2453 0 : ' src_c=',trim(modes%comps(m)%source_mmr_c(i)), ' mmr_c=',trim(modes%comps(m)%camname_mmr_c(i)), &
2454 0 : ' type=',trim(modes%comps(m)%type(i))
2455 0 : write(iulog,*) ' prop file=', trim(modes%comps(m)%props(i))
2456 : end do
2457 :
2458 : end do
2459 :
2460 0 : end subroutine print_modes
2461 :
2462 : !================================================================================================
2463 :
2464 2 : subroutine print_lists(gas_list, aer_list, ma_list)
2465 :
2466 : ! Print summary of gas, bulk and modal aerosol lists. This is just the information
2467 : ! read from the namelist.
2468 :
2469 : use radconstants, only: gascnst=>gaslist
2470 :
2471 : type(aerlist_t), intent(in) :: aer_list
2472 : type(gaslist_t), intent(in) :: gas_list
2473 : type(modelist_t), intent(in) :: ma_list
2474 :
2475 : integer :: i, id
2476 :
2477 2 : if (len_trim(gas_list%list_id) == 0) then
2478 2 : write(iulog,*) nl//' gas list for climate calculations'
2479 : else
2480 0 : write(iulog,*) nl//' gas list for diag'//gas_list%list_id//' calculations'
2481 : end if
2482 :
2483 18 : do i = 1, nradgas
2484 18 : if (gas_list%gas(i)%source .eq. 'N') then
2485 14 : write(iulog,*) ' '//gas_list%gas(i)%source//':'//gascnst(i)//' has pbuf name:'//&
2486 28 : trim(gas_list%gas(i)%camname)
2487 2 : else if (gas_list%gas(i)%source .eq. 'A') then
2488 2 : write(iulog,*) ' '//gas_list%gas(i)%source//':'//gascnst(i)//' has constituents name:'//&
2489 4 : trim(gas_list%gas(i)%camname)
2490 : endif
2491 : enddo
2492 :
2493 2 : if (len_trim(aer_list%list_id) == 0) then
2494 2 : write(iulog,*) nl//' bulk aerosol list for climate calculations'
2495 : else
2496 0 : write(iulog,*) nl//' bulk aerosol list for diag'//aer_list%list_id//' calculations'
2497 : end if
2498 :
2499 2 : do i = 1, aer_list%numaerosols
2500 0 : write(iulog,*) ' '//trim(aer_list%aer(i)%source)//':'//trim(aer_list%aer(i)%camname)//&
2501 2 : ' optics and phys props in :'//trim(aer_list%aer(i)%physprop_file)
2502 : enddo
2503 :
2504 2 : if (len_trim(ma_list%list_id) == 0) then
2505 2 : write(iulog,*) nl//' modal aerosol list for climate calculations'
2506 : else
2507 0 : write(iulog,*) nl//' modal aerosol list for diag'//ma_list%list_id//' calculations'
2508 : end if
2509 :
2510 2 : do i = 1, ma_list%nmodes
2511 0 : id = ma_list%idx(i)
2512 2 : write(iulog,*) ' '//trim(modes%names(id))
2513 : enddo
2514 :
2515 2 : end subroutine print_lists
2516 :
2517 : !================================================================================================
2518 :
2519 0 : end module rad_constituents
|