Line data Source code
1 : module scamMod
2 : !----------------------------------------------------------------------
3 : !
4 : ! This module provides control variables and namelist functionality
5 : ! for SCAM.
6 : !
7 : ! As with global CAM, SCAM is initialized with state information
8 : ! from the initial and boundary files. For each succeeding timestep
9 : ! SCAM calculates the physics tendencies and combines these with
10 : ! the advective tendencies provided by the IOP file to produce
11 : ! a forcast. Generally, the control variables in this module
12 : ! determine what data and parameterizations will be used to make
13 : ! the forecast. For instance, many of the control variables in
14 : ! this module provide flexibility to affect the forecast by overriding
15 : ! parameterization prognosed tendencies with observed tendencies
16 : ! of a particular field program recorded on the IOP file.
17 : !
18 : ! Public functions/subroutines:
19 : ! scam_readnl
20 : !-----------------------------------------------------------------------
21 :
22 : use shr_kind_mod, only: r8 => shr_kind_r8
23 : use pmgrid, only: plon, plat, plev, plevp
24 : use constituents, only: pcnst
25 : use shr_scam_mod, only: shr_scam_getCloseLatLon
26 : use dycore, only: dycore_is
27 : use cam_logfile, only: iulog
28 : use cam_abortutils, only: endrun
29 :
30 : implicit none
31 : private
32 :
33 : ! PUBLIC INTERFACES:
34 :
35 : public scam_readnl ! read SCAM namelist options
36 :
37 : ! PUBLIC MODULE DATA:
38 :
39 : real(r8), public :: pressure_levels(plev)
40 : real(r8), public :: scmlat ! input namelist latitude for scam
41 : real(r8), public :: scmlon ! input namelist longitude for scam
42 :
43 :
44 : integer, parameter :: num_switches = 20
45 : integer, parameter :: max_path_len = 128
46 :
47 : logical, public :: single_column ! Using IOP file or not
48 : logical, public :: use_iop ! Using IOP file or not
49 : logical, public :: use_pert_init ! perturb initial values
50 : logical, public :: use_pert_frc ! perturb forcing
51 : logical, public :: switch(num_switches) ! Logical flag settings from GUI
52 : logical, public :: l_uvphys ! If true, update u/v after TPHYS
53 : logical, public :: l_uvadvect ! If true, T, U & V will be passed to SLT
54 : logical, public :: l_conv ! use flux divergence terms for T and q?
55 : logical, public :: l_divtr ! use flux divergence terms for constituents?
56 : logical, public :: l_diag ! do we want available diagnostics?
57 :
58 : integer, public :: error_code ! Error code from netCDF reads
59 : integer, public :: initTimeIdx
60 : integer, public :: seedval
61 :
62 : character*(max_path_len), public :: modelfile
63 : character*(max_path_len), public :: analysisfile
64 : character*(max_path_len), public :: sicfile
65 : character*(max_path_len), public :: userfile
66 : character*(max_path_len), public :: sstfile
67 : character*(max_path_len), public :: lsmpftfile
68 : character*(max_path_len), public :: pressfile
69 : character*(max_path_len), public :: topofile
70 : character*(max_path_len), public :: ozonefile
71 : character*(max_path_len), public :: iopfile
72 : character*(max_path_len), public :: absemsfile
73 : character*(max_path_len), public :: aermassfile
74 : character*(max_path_len), public :: aeropticsfile
75 : character*(max_path_len), public :: timeinvfile
76 : character*(max_path_len), public :: lsmsurffile
77 : character*(max_path_len), public :: lsminifile
78 :
79 : ! note that scm_zadv_q is set to slt to be consistent with CAM BFB testing
80 :
81 :
82 : character(len=16), public :: scm_zadv_T = 'eulc '
83 : character(len=16), public :: scm_zadv_q = 'slt '
84 : character(len=16), public :: scm_zadv_uv = 'eulc '
85 :
86 : real(r8), public :: fixmascam
87 : real(r8), public :: betacam
88 : real(r8), public :: alphacam(pcnst)
89 : real(r8), public :: dqfxcam(plon,plev,pcnst)
90 :
91 : real(r8), public :: divq3d(plev,pcnst) ! 3D q advection
92 : real(r8), public :: divt3d(plev) ! 3D T advection
93 : real(r8), public :: divu3d(plev) ! 3D U advection
94 : real(r8), public :: divv3d(plev) ! 3D V advection
95 : real(r8), public :: vertdivq(plev,pcnst)! vertical q advection
96 : real(r8), public :: vertdivt(plev) ! vertical T advection
97 : real(r8), public :: vertdivu(plev) ! vertical T advection
98 : real(r8), public :: vertdivv(plev) ! vertical T advection
99 : real(r8), public :: ptend ! surface pressure tendency
100 : real(r8), public :: qdiff(plev) ! model minus observed humidity
101 : real(r8), public :: qobs(plev) ! actual W.V. Mixing ratio
102 : real(r8), public :: qinitobs(plev,pcnst)! initial tracer field
103 : real(r8), public :: cldliqobs(plev) ! actual W.V. Mixing ratio
104 : real(r8), public :: cldiceobs(plev) ! actual W.V. Mixing ratio
105 : real(r8), public :: numliqobs(plev) ! actual
106 : real(r8), public :: numiceobs(plev) ! actual
107 : real(r8), public :: precobs(1) ! observed precipitation
108 : real(r8), public :: lhflxobs(1) ! observed surface latent heat flux
109 : real(r8), public :: shflxobs(1) ! observed surface sensible heat flux
110 : real(r8), public :: q1obs(plev) ! observed apparent heat source
111 : real(r8), public :: q2obs(plev) ! observed apparent heat sink
112 : real(r8), public :: tdiff(plev) ! model minus observed temp
113 : real(r8), public :: tground(1) ! ground temperature
114 : real(r8), public :: tobs(plev) ! actual temperature
115 : real(r8), public :: tsair(1) ! air temperature at the surface
116 : real(r8), public :: udiff(plev) ! model minus observed uwind
117 : real(r8), public :: uobs(plev) ! actual u wind
118 : real(r8), public :: vdiff(plev) ! model minus observed vwind
119 : real(r8), public :: vobs(plev) ! actual v wind
120 : real(r8), public :: cldobs(plev) ! observed cld
121 : real(r8), public :: clwpobs(plev) ! observed clwp
122 : real(r8), public :: aldirobs(1) ! observed aldir
123 : real(r8), public :: aldifobs(1) ! observed aldif
124 : real(r8), public :: asdirobs(1) ! observed asdir
125 : real(r8), public :: asdifobs(1) ! observed asdif
126 :
127 : real(r8), public :: wfld(plev) ! Vertical motion (slt)
128 : real(r8), public :: wfldh(plevp) ! Vertical motion (slt)
129 : real(r8), public :: divq(plev,pcnst) ! Divergence of moisture
130 : real(r8), public :: divt(plev) ! Divergence of temperature
131 : real(r8), public :: divu(plev) ! Horiz Divergence of E/W
132 : real(r8), public :: divv(plev) ! Horiz Divergence of N/S
133 : ! mo_drydep algorithm
134 : real(r8), public, pointer :: loniop(:)
135 : real(r8), public, pointer :: latiop(:)
136 :
137 : integer, public :: iopTimeIdx ! index into iop dataset
138 : integer, public :: steplength ! Length of time-step
139 : integer, public :: base_date ! Date in (yyyymmdd) of start time
140 : integer, public :: base_secs ! Time of day of start time (sec)
141 :
142 : ! SCAM public data defaults
143 :
144 : logical, public :: doiopupdate = .false. ! do we need to read next iop timepoint
145 : logical, public :: have_lhflx = .false. ! dataset contains lhflx
146 : logical, public :: have_shflx = .false. ! dataset contains shflx
147 : logical, public :: have_tg = .false. ! dataset contains tg
148 : logical, public :: have_tsair = .false. ! dataset contains tsair
149 : logical, public :: have_divq = .false. ! dataset contains divq
150 : logical, public :: have_divt = .false. ! dataset contains divt
151 : logical, public :: have_divq3d = .false. ! dataset contains divq3d
152 : logical, public :: have_vertdivu = .false. ! dataset contains vertdivu
153 : logical, public :: have_vertdivv = .false. ! dataset contains vertdivv
154 : logical, public :: have_vertdivt = .false. ! dataset contains vertdivt
155 : logical, public :: have_vertdivq = .false. ! dataset contains vertdivq
156 : logical, public :: have_divt3d = .false. ! dataset contains divt3d
157 : logical, public :: have_divu3d = .false. ! dataset contains divu3d
158 : logical, public :: have_divv3d = .false. ! dataset contains divv3d
159 : logical, public :: have_divu = .false. ! dataset contains divu
160 : logical, public :: have_divv = .false. ! dataset contains divv
161 : logical, public :: have_omega = .false. ! dataset contains omega
162 : logical, public :: have_phis = .false. ! dataset contains phis
163 : logical, public :: have_ptend = .false. ! dataset contains ptend
164 : logical, public :: have_ps = .false. ! dataset contains ps
165 : logical, public :: have_q = .false. ! dataset contains q
166 : logical, public :: have_q1 = .false. ! dataset contains Q1
167 : logical, public :: have_q2 = .false. ! dataset contains Q2
168 : logical, public :: have_prec = .false. ! dataset contains prec
169 : logical, public :: have_t = .false. ! dataset contains t
170 : logical, public :: have_u = .false. ! dataset contains u
171 : logical, public :: have_v = .false. ! dataset contains v
172 : logical, public :: have_cld = .false. ! dataset contains cld
173 : logical, public :: have_cldliq = .false. ! dataset contains cldliq
174 : logical, public :: have_cldice = .false. ! dataset contains cldice
175 : logical, public :: have_numliq = .false. ! dataset contains numliq
176 : logical, public :: have_numice = .false. ! dataset contains numice
177 : logical, public :: have_clwp = .false. ! dataset contains clwp
178 : logical, public :: have_aldir = .false. ! dataset contains aldir
179 : logical, public :: have_aldif = .false. ! dataset contains aldif
180 : logical, public :: have_asdir = .false. ! dataset contains asdir
181 : logical, public :: have_asdif = .false. ! dataset contains asdif
182 : logical, public :: use_camiop = .false. ! use cam generated forcing
183 : logical, public :: use_3dfrc = .false. ! use 3d forcing
184 : logical, public :: isrestart = .false. ! If this is a restart step or not
185 :
186 : ! SCAM namelist defaults
187 :
188 : logical, public :: scm_backfill_iop_w_init = .false. ! Backfill missing IOP data from initial file
189 : logical, public :: scm_relaxation = .false. ! Use relaxation
190 : logical, public :: scm_crm_mode = .false. ! Use column radiation mode
191 : logical, public :: scm_cambfb_mode = .false. ! Use extra CAM IOP fields to assure bit for bit match with CAM run
192 : logical, public :: scm_use_obs_T = .false. ! Use the SCAM-IOP specified observed T at each time step instead of forecasting.
193 : logical, public :: scm_force_latlon = .false. ! force scam to use the lat lon fields specified in the scam namelist not what is closest to iop avail lat lon
194 : real*8, public :: scm_relax_top_p = 1.e36_r8 ! upper bound for scm relaxation
195 : real*8, public :: scm_relax_bot_p = -1.e36_r8 ! lower bound for scm relaxation
196 : real*8, public :: scm_relax_tau_sec = 10800._r8 ! relaxation time constant (sec)
197 :
198 : ! +++BPM:
199 : ! modification... allow a linear ramp in relaxation time scale:
200 : logical, public :: scm_relax_linear = .false.
201 : real*8, public :: scm_relax_tau_bot_sec = 10800._r8
202 : real*8, public :: scm_relax_tau_top_sec = 10800._r8
203 : character(len=26), public :: scm_relax_fincl(pcnst)
204 :
205 : !
206 : ! note that scm_use_obs_uv is set to true to be consistent with CAM BFB testing
207 : !
208 :
209 : logical, public :: scm_use_obs_uv = .true. ! Use the SCAM-IOP specified observed u,v at each time step instead of forecasting.
210 :
211 : logical, public :: scm_use_obs_qv = .false. ! Use the SCAM-IOP specified observed qv at each time step instead of forecasting.
212 : logical, public :: scm_iop_lhflxshflxTg = .false. !turn off LW rad
213 : logical, public :: scm_iop_Tg = .false. !turn off LW rad
214 :
215 : character(len=200), public :: scm_clubb_iop_name ! IOP name for CLUBB
216 :
217 : !=======================================================================
218 : contains
219 : !=======================================================================
220 :
221 1536 : subroutine scam_readnl(nlfile,single_column_in,scmlat_in,scmlon_in)
222 :
223 : use namelist_utils, only: find_group_name
224 : use units, only: getunit, freeunit
225 : use dycore, only: dycore_is
226 : use wrap_nf, only: wrap_open
227 : use spmd_utils, only : masterproc,npes
228 : use netcdf, only : nf90_inquire_attribute,NF90_NOERR,NF90_GLOBAL,NF90_NOWRITE
229 :
230 :
231 : !---------------------------Arguments-----------------------------------
232 :
233 : character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input (nlfile=atm_in)
234 : logical, intent(in) :: single_column_in
235 : real(r8), intent(in) :: scmlat_in
236 : real(r8), intent(in) :: scmlon_in
237 :
238 : ! Local variables
239 : character(len=*), parameter :: sub = 'scam_readnl'
240 : integer :: unitn, ierr, i
241 : integer :: ncid
242 : integer :: iatt
243 : integer :: latidx, lonidx
244 : logical :: adv
245 : real(r8) :: ioplat,ioplon
246 :
247 : ! this list should include any variable that you might want to include in the namelist
248 : namelist /scam_nl/ iopfile, scm_iop_lhflxshflxTg, scm_iop_Tg, scm_relaxation, &
249 : scm_relax_top_p,scm_relax_bot_p,scm_relax_tau_sec, &
250 : scm_cambfb_mode,scm_crm_mode,scm_zadv_uv,scm_zadv_T,scm_zadv_q,&
251 : scm_use_obs_T, scm_use_obs_uv, scm_use_obs_qv, &
252 : scm_relax_linear, scm_relax_tau_top_sec, &
253 : scm_relax_tau_bot_sec, scm_force_latlon, scm_relax_fincl, scm_backfill_iop_w_init
254 :
255 1536 : single_column=single_column_in
256 :
257 1536 : iopfile = ' '
258 1536 : scm_clubb_iop_name = ' '
259 64512 : scm_relax_fincl(:) = ' '
260 :
261 1536 : if( single_column ) then
262 0 : if( npes.gt.1) call endrun('SCAM_READNL: SCAM doesnt support using more than 1 pe.')
263 :
264 0 : if (.not. dycore_is('EUL') .or. plon /= 1 .or. plat /=1 ) then
265 0 : call endrun('SCAM_SETOPTS: must compile model for SCAM mode when namelist parameter single_column is .true.')
266 : endif
267 :
268 0 : scmlat=scmlat_in
269 0 : scmlon=scmlon_in
270 :
271 0 : if( scmlat .lt. -90._r8 .or. scmlat .gt. 90._r8 ) then
272 0 : call endrun('SCAM_READNL: SCMLAT must be between -90. and 90. degrees.')
273 0 : elseif( scmlon .lt. 0._r8 .or. scmlon .gt. 360._r8 ) then
274 0 : call endrun('SCAM_READNL: SCMLON must be between 0. and 360. degrees.')
275 : end if
276 :
277 : ! Read namelist
278 0 : if (masterproc) then
279 0 : unitn = getunit()
280 0 : open( unitn, file=trim(nlfile), status='old' )
281 0 : call find_group_name(unitn, 'scam_nl', status=ierr)
282 0 : if (ierr == 0) then
283 0 : read(unitn, scam_nl, iostat=ierr)
284 0 : if (ierr /= 0) then
285 0 : call endrun(sub // ':: ERROR reading namelist')
286 : end if
287 : end if
288 0 : close(unitn)
289 0 : call freeunit(unitn)
290 : end if
291 :
292 : ! Error checking:
293 :
294 0 : iopfile = trim(iopfile)
295 0 : if( iopfile .ne. "" ) then
296 0 : use_iop = .true.
297 : else
298 0 : call endrun('SCAM_READNL: must specify IOP file for single column mode')
299 : endif
300 :
301 0 : call wrap_open( iopfile, NF90_NOWRITE, ncid )
302 :
303 0 : if( nf90_inquire_attribute( ncid, NF90_GLOBAL, 'CAM_GENERATED_FORCING', iatt ) .EQ. NF90_NOERR ) then
304 0 : use_camiop = .true.
305 : else
306 0 : use_camiop = .false.
307 : endif
308 :
309 : ! If we are not forcing the lat and lon from the namelist use the closest lat and lon that is found in the IOP file.
310 0 : if (.not.scm_force_latlon) then
311 0 : call shr_scam_GetCloseLatLon( ncid, scmlat, scmlon, ioplat, ioplon, latidx, lonidx )
312 0 : write(iulog,*) 'SCAM_READNL: using closest IOP column to lat/lon specified in drv_in'
313 0 : write(iulog,*) ' requested lat,lon =',scmlat,', ',scmlon
314 0 : write(iulog,*) ' closest IOP lat,lon =',ioplat,', ',ioplon
315 :
316 0 : scmlat = ioplat
317 0 : scmlon = ioplon
318 : end if
319 :
320 0 : if (masterproc) then
321 0 : write (iulog,*) 'Single Column Model Options: '
322 0 : write (iulog,*) '============================='
323 0 : write (iulog,*) ' iopfile = ',trim(iopfile)
324 0 : write (iulog,*) ' scm_backfill_iop_w_init = ',scm_backfill_iop_w_init
325 0 : write (iulog,*) ' scm_cambfb_mode = ',scm_cambfb_mode
326 0 : write (iulog,*) ' scm_crm_mode = ',scm_crm_mode
327 0 : write (iulog,*) ' scm_force_latlon = ',scm_force_latlon
328 0 : write (iulog,*) ' scm_iop_Tg = ',scm_iop_Tg
329 0 : write (iulog,*) ' scm_iop_lhflxshflxTg = ',scm_iop_lhflxshflxTg
330 0 : write (iulog,*) ' scm_relaxation = ',scm_relaxation
331 0 : write (iulog,*) ' scm_relax_bot_p = ',scm_relax_bot_p
332 0 : write (iulog,*) ' scm_relax_linear = ',scm_relax_linear
333 0 : write (iulog,*) ' scm_relax_tau_bot_sec = ',scm_relax_tau_bot_sec
334 0 : write (iulog,*) ' scm_relax_tau_sec = ',scm_relax_tau_sec
335 0 : write (iulog,*) ' scm_relax_tau_top_sec = ',scm_relax_tau_top_sec
336 0 : write (iulog,*) ' scm_relax_top_p = ',scm_relax_top_p
337 0 : write (iulog,*) ' scm_use_obs_T = ',scm_use_obs_T
338 0 : write (iulog,*) ' scm_use_obs_qv = ',scm_use_obs_qv
339 0 : write (iulog,*) ' scm_use_obs_uv = ',scm_use_obs_uv
340 0 : write (iulog,*) ' scm_zadv_T = ',trim(scm_zadv_T)
341 0 : write (iulog,*) ' scm_zadv_q = ',trim(scm_zadv_q)
342 0 : write (iulog,*) ' scm_zadv_uv = ',trim(scm_zadv_uv)
343 0 : write (iulog,*) ' scm_relax_finc: '
344 : ! output scm_relax_fincl character array
345 0 : do i=1,pcnst
346 0 : if (scm_relax_fincl(i) .ne. '') then
347 0 : adv = mod(i,4)==0
348 0 : if (adv) then
349 0 : write (iulog, "(A18)") "'"//trim(scm_relax_fincl(i))//"',"
350 : else
351 0 : write (iulog, "(A18)", ADVANCE="NO") "'"//trim(scm_relax_fincl(i))//"',"
352 : end if
353 : else
354 : exit
355 : end if
356 : end do
357 0 : print *
358 : end if
359 : end if
360 :
361 1536 : end subroutine scam_readnl
362 :
363 : !===============================================================================
364 :
365 : end module scamMod
|