module radiation 10,11 !--------------------------------------------------------------------------------- ! Purpose: ! ! Provides the CAM interface to the radiation code ! ! Revision history: ! May 2004, D. B. Coleman, Initial version of interface module. ! July 2004, B. Eaton, Use interfaces from new shortwave, longwave, and ozone modules. ! Feb 2005, B. Eaton, Add namelist variables and control of when calcs are done. ! Mar 2008, J. Kay, Add FLDS (downwelling LW rad at surface) as an outfld. ! May 2008, J. Kay, ADD FSUTOA (upwelling SW radiation at TOA) as an outfld. ! Sep 2009, R. Neale, Add FLDSC (clear sky downwelling LW rad at surface) as an outfld. !--------------------------------------------------------------------------------- use shr_kind_mod, only: r8=>shr_kind_r8 use spmd_utils, only: masterproc use ppgrid, only: pcols, pver, pverp use physics_types, only: physics_state, physics_ptend use physconst, only: cpair, cappa use time_manager, only: get_nstep use abortutils, only: endrun use error_messages, only: handle_err use cam_control_mod, only: lambm0, obliqr, mvelpp, eccen use scamMod, only: scm_crm_mode, single_column,have_cld,cldobs,& have_clwp,clwpobs,have_tg,tground use perf_mod, only: t_startf, t_stopf use cam_logfile, only: iulog implicit none private save public :: & radiation_register, &! registers radiation physics buffer fields radiation_defaultopts, &! set default values of namelist variables in runtime_opts radiation_setopts, &! set namelist values from runtime_opts radiation_printopts, &! print namelist values to log radiation_get, &! provide read access to private module data radiation_nextsw_cday, &! calendar day of next radiation calculation radiation_do, &! query which radiation calcs are done this timestep radiation_init, &! calls radini radiation_tend ! moved from radctl.F90 ! Private module data ! Default values for namelist variables integer :: iradsw = -1 ! freq. of shortwave radiation calc in time steps (positive) ! or hours (negative). integer :: iradlw = -1 ! frequency of longwave rad. calc. in time steps (positive) ! or hours (negative). integer :: iradae = -12 ! frequency of absorp/emis calc in time steps (positive) ! or hours (negative). integer :: irad_always = 0 ! Specifies length of time in timesteps (positive) ! or hours (negative) SW/LW radiation will be ! run continuously from the start of an ! initial or restart run !=============================================================================== contains !=============================================================================== subroutine radiation_register 1,3 !----------------------------------------------------------------------- ! ! Register radiation fields in the physics buffer ! !----------------------------------------------------------------------- use phys_buffer, only: pbuf_times, pbuf_add integer idx call pbuf_add('QRS' , 'global', 1,pver,1, idx) ! shortwave radiative heating rate call pbuf_add('QRL' , 'global', 1,pver,1, idx) ! longwave radiative heating rate end subroutine radiation_register !================================================================================================ subroutine radiation_defaultopts(iradsw_out, iradlw_out, iradae_out, irad_always_out) 1 !----------------------------------------------------------------------- ! Purpose: Return default runtime options !----------------------------------------------------------------------- integer, intent(out), optional :: iradsw_out integer, intent(out), optional :: iradlw_out integer, intent(out), optional :: iradae_out integer, intent(out), optional :: irad_always_out !----------------------------------------------------------------------- if ( present(iradsw_out) ) iradsw_out = iradsw if ( present(iradlw_out) ) iradlw_out = iradlw if ( present(iradae_out) ) iradae_out = iradae if ( present(irad_always_out) ) irad_always_out = irad_always end subroutine radiation_defaultopts !================================================================================================ subroutine radiation_setopts(dtime, nhtfrq, iradsw_in, iradlw_in, iradae_in, & 1,1 irad_always_in) !----------------------------------------------------------------------- ! Purpose: Set runtime options ! *** NOTE *** This routine needs information about dtime (init by dycore) ! and nhtfrq (init by history) to do its checking. Being called ! from runtime_opts provides these values possibly before they ! have been set in the modules responsible for them. !----------------------------------------------------------------------- integer, intent(in) :: dtime ! timestep size (s) integer, intent(in) :: nhtfrq ! output frequency of primary history file integer, intent(in), optional :: iradsw_in integer, intent(in), optional :: iradlw_in integer, intent(in), optional :: iradae_in integer, intent(in), optional :: irad_always_in ! Local integer :: ntspdy ! no. timesteps per day integer :: nhtfrq1 ! local copy of input arg nhtfrq !----------------------------------------------------------------------- if ( present(iradsw_in) ) iradsw = iradsw_in if ( present(iradlw_in) ) iradlw = iradlw_in if ( present(iradae_in) ) iradae = iradae_in if ( present(irad_always_in) ) irad_always = irad_always_in ! Convert iradsw, iradlw and irad_always from hours to timesteps if necessary if (iradsw < 0) iradsw = nint((-iradsw *3600._r8)/dtime) if (iradlw < 0) iradlw = nint((-iradlw *3600._r8)/dtime) if (irad_always < 0) irad_always = nint((-irad_always*3600._r8)/dtime) ! Convert iradae from hours to timesteps if necessary and check that ! iradae must be an even multiple of iradlw if (iradae < 0) iradae = nint((-iradae*3600._r8)/dtime) if (mod(iradae,iradlw)/=0) then write(iulog,*)'radiation_setopts: iradae must be an even multiple of iradlw.' write(iulog,*)' iradae = ',iradae,', iradlw = ',iradlw call endrun('radiation_setopts: iradae must be an even multiple of iradlw.') end if ! Do absorptivities/emissivities have to go on a restart dataset? ! The value of nhtfrq from the namelist may need conversion. nhtfrq1 = nhtfrq if (nhtfrq1 < 0) nhtfrq1 = nint((-nhtfrq1*3600._r8)/dtime) ntspdy = nint(86400._r8/dtime) if (nhtfrq1 /= 0) then if (masterproc .and. mod(nhtfrq1,iradae)/=0) then write(iulog,*)'radiation_setopts: *** NOTE: Extra overhead invoked putting', & ' a/e numbers on restart dataset. *** ', & ' To avoid, make mod(nhtfrq,iradae) = 0' end if else if (masterproc) then if (mod(ntspdy,iradae) /= 0 .or. iradae > ntspdy) then write(iulog,*)'radiation_setopts: *** NOTE: Extra overhead invoked', & ' putting a/e numbers on restart dataset. ***' write(iulog,*)' To avoid, make mod(timesteps per day,iradae)= 0' end if end if end if end subroutine radiation_setopts !=============================================================================== subroutine radiation_get(iradsw_out, iradlw_out, iradae_out, irad_always_out) !----------------------------------------------------------------------- ! Purpose: Provide access to private module data. (This should be eliminated.) !----------------------------------------------------------------------- integer, intent(out), optional :: iradsw_out integer, intent(out), optional :: iradlw_out integer, intent(out), optional :: iradae_out integer, intent(out), optional :: irad_always_out !----------------------------------------------------------------------- if ( present(iradsw_out) ) iradsw_out = iradsw if ( present(iradlw_out) ) iradlw_out = iradlw if ( present(iradae_out) ) iradae_out = iradae if ( present(irad_always_out) ) irad_always_out = irad_always end subroutine radiation_get !================================================================================================ subroutine radiation_printopts 1 !----------------------------------------------------------------------- ! Purpose: Print runtime options to log. !----------------------------------------------------------------------- if(irad_always /= 0) write(iulog,10) irad_always write(iulog,20) iradsw,iradlw,iradae 10 format(' Execute SW/LW radiation continuously for the first ',i5, ' timestep(s) of this run') 20 format(' Frequency of Shortwave Radiation calc. (IRADSW) ',i5/, & ' Frequency of Longwave Radiation calc. (IRADLW) ',i5/, & ' Frequency of Absorptivity/Emissivity calc. (IRADAE) ',i5) end subroutine radiation_printopts !================================================================================================ function radiation_do(op, timestep) 8,2 !----------------------------------------------------------------------- ! Purpose: Returns true if the specified operation is done this timestep. !----------------------------------------------------------------------- character(len=*), intent(in) :: op ! name of operation integer, intent(in), optional:: timestep logical :: radiation_do ! return value ! Local variables integer :: nstep ! current timestep number !----------------------------------------------------------------------- if (present(timestep)) then nstep = timestep else nstep = get_nstep() end if select case (op) case ('sw') ! do a shortwave heating calc this timestep? radiation_do = nstep == 0 .or. iradsw == 1 & .or. (mod(nstep-1,iradsw) == 0 .and. nstep /= 1) & .or. nstep <= irad_always case ('lw') ! do a longwave heating calc this timestep? radiation_do = nstep == 0 .or. iradlw == 1 & .or. (mod(nstep-1,iradlw) == 0 .and. nstep /= 1) & .or. nstep <= irad_always case ('absems') ! do an absorptivity/emissivity calculation this timestep? radiation_do = nstep == 0 .or. iradae == 1 & .or. (mod(nstep-1,iradae) == 0 .and. nstep /= 1) case ('aeres') ! write absorptivity/emissivity to restart file this timestep? radiation_do = mod(nstep,iradae) /= 0 case default call endrun('radiation_do: unknown operation:'//op) end select end function radiation_do !================================================================================================ real(r8) function radiation_nextsw_cday() 4,6 !----------------------------------------------------------------------- ! Purpose: Returns calendar day of next sw radiation calculation !----------------------------------------------------------------------- use time_manager, only: get_curr_calday, get_nstep, get_step_size ! Local variables integer :: nstep ! timestep counter logical :: dosw ! true => do shosrtwave calc integer :: offset ! offset for calendar day calculation integer :: dTime ! integer timestep size real(r8):: calday ! calendar day of !----------------------------------------------------------------------- radiation_nextsw_cday = -1._r8 dosw = .false. nstep = get_nstep() dtime = get_step_size() offset = 0 do while (.not. dosw) nstep = nstep + 1 offset = offset + dtime if (radiation_do('sw', nstep)) then radiation_nextsw_cday = get_curr_calday(offset=offset) dosw = .true. end if end do if(radiation_nextsw_cday == -1._r8) then call endrun('error in radiation_nextsw_cday') end if end function radiation_nextsw_cday !================================================================================================ subroutine radiation_init() 1,106 !----------------------------------------------------------------------- ! ! Initialize the radiation parameterization, add fields to the history buffer ! !----------------------------------------------------------------------- use cam_history, only: addfld, add_default, phys_decomp use physconst, only: gravit, cpair, epsilo, stebol, & pstd, mwdry, mwco2, mwo3 use param_cldoptics, only: param_cldoptics_init use radsw, only: radsw_init use radlw, only: radlw_init use radae, only: radae_init use cloudsimulator, only: doisccp, cloudsimulator_init use radconstants, only: radconstants_init use radiation_data, only: init_rad_data integer :: nstep ! current timestep number !----------------------------------------------------------------------- call radconstants_init() call init_rad_data() call radsw_init(gravit) call radlw_init(gravit, stebol) call radae_init(gravit, epsilo, stebol, pstd, mwdry, mwco2, mwo3) call param_cldoptics_init ! "irad_always" is number of time steps to execute radiation continuously from start of ! initial OR restart run nstep = get_nstep() if ( irad_always > 0) then nstep = get_nstep() irad_always = irad_always + nstep end if if (doisccp) call cloudsimulator_init ! Shortwave radiation call addfld ('SOLIN ','W/m2 ',1, 'A','Solar insolation',phys_decomp, sampling_seq='rad_lwsw') call addfld ('SOLL ','W/m2 ',1, 'A','Solar downward near infrared direct to surface',phys_decomp, & sampling_seq='rad_lwsw') call addfld ('SOLS ','W/m2 ',1, 'A','Solar downward visible direct to surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('SOLLD ','W/m2 ',1, 'A','Solar downward near infrared diffuse to surface',phys_decomp, & sampling_seq='rad_lwsw') call addfld ('SOLSD ','W/m2 ',1, 'A','Solar downward visible diffuse to surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('QRS ','K/s ',pver, 'A','Solar heating rate',phys_decomp, sampling_seq='rad_lwsw') call addfld ('QRSC ','K/s ',pver, 'A','Clearsky solar heating rate',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNS ','W/m2 ',1, 'A','Net solar flux at surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNT ','W/m2 ',1, 'A','Net solar flux at top of model',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNTOA ','W/m2 ',1, 'A','Net solar flux at top of atmosphere',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSUTOA ','W/m2 ',1, 'A','Upwelling solar flux at top of atmosphere',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNTOAC ','W/m2 ',1, 'A','Clearsky net solar flux at top of atmosphere',phys_decomp, & sampling_seq='rad_lwsw') call addfld ('FSDTOA ','W/m2 ',1, 'A','Downwelling solar flux at top of atmosphere',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSN200 ','W/m2 ',1, 'A','Net shortwave flux at 200 mb',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSN200C ','W/m2 ',1, 'A','Clearsky net shortwave flux at 200 mb',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNTC ','W/m2 ',1, 'A','Clearsky net solar flux at top of model',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNSC ','W/m2 ',1, 'A','Clearsky net solar flux at surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSDSC ','W/m2 ',1, 'A','Clearsky downwelling solar flux at surface',phys_decomp, & sampling_seq='rad_lwsw') call addfld ('FSDS ','W/m2 ',1, 'A','Downwelling solar flux at surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FUS ','W/m2 ',pverp,'I','Shortwave upward flux',phys_decomp) call addfld ('FDS ','W/m2 ',pverp,'I','Shortwave downward flux',phys_decomp) call addfld ('FUSC ','W/m2 ',pverp,'I','Shortwave clear-sky upward flux',phys_decomp) call addfld ('FDSC ','W/m2 ',pverp,'I','Shortwave clear-sky downward flux',phys_decomp) call addfld ('FSNIRTOA','W/m2 ',1, 'A','Net near-infrared flux (Nimbus-7 WFOV) at top of atmosphere', & phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNRTOAC','W/m2 ',1, 'A','Clearsky net near-infrared flux (Nimbus-7 WFOV) at top of atmosphere', & phys_decomp, sampling_seq='rad_lwsw') call addfld ('FSNRTOAS','W/m2 ',1, 'A','Net near-infrared flux (>= 0.7 microns) at top of atmosphere',phys_decomp, & sampling_seq='rad_lwsw') call addfld ('SWCF ','W/m2 ',1, 'A','Shortwave cloud forcing',phys_decomp, sampling_seq='rad_lwsw') call add_default ('SOLIN ', 1, ' ') call add_default ('QRS ', 1, ' ') call add_default ('FSNS ', 1, ' ') call add_default ('FSNT ', 1, ' ') call add_default ('FSDTOA ', 1, ' ') call add_default ('FSNTOA ', 1, ' ') call add_default ('FSUTOA ', 1, ' ') call add_default ('FSNTOAC ', 1, ' ') call add_default ('FSNTC ', 1, ' ') call add_default ('FSNSC ', 1, ' ') call add_default ('FSDSC ', 1, ' ') call add_default ('FSDS ', 1, ' ') call add_default ('SWCF ', 1, ' ') if (single_column.and.scm_crm_mode) then call add_default ('FUS ', 1, ' ') call add_default ('FUSC ', 1, ' ') call add_default ('FDS ', 1, ' ') call add_default ('FDSC ', 1, ' ') endif ! Longwave radiation call addfld ('QRL ','K/s ',pver, 'A','Longwave heating rate',phys_decomp, sampling_seq='rad_lwsw') call addfld ('QRLC ','K/s ',pver, 'A','Clearsky longwave heating rate',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLNS ','W/m2 ',1, 'A','Net longwave flux at surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLDS ','W/m2 ',1, 'A','Downwelling longwave flux at surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLNT ','W/m2 ',1, 'A','Net longwave flux at top of model',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLUT ','W/m2 ',1, 'A','Upwelling longwave flux at top of model',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLUTC ','W/m2 ',1, 'A','Clearsky upwelling longwave flux at top of model',phys_decomp, & sampling_seq='rad_lwsw') call addfld ('FLNTC ','W/m2 ',1, 'A','Clearsky net longwave flux at top of model',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLN200 ','W/m2 ',1, 'A','Net longwave flux at 200 mb',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLN200C ','W/m2 ',1, 'A','Clearsky net longwave flux at 200 mb',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLNSC ','W/m2 ',1, 'A','Clearsky net longwave flux at surface',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FLDSC ','W/m2 ',1, 'A','Clearsky downwelling longwave flux at surface',phys_decomp, & sampling_seq='rad_lwsw') call addfld ('LWCF ','W/m2 ',1, 'A','Longwave cloud forcing',phys_decomp, sampling_seq='rad_lwsw') call addfld ('FUL ','W/m2 ',pverp,'I','Longwave upward flux',phys_decomp) call addfld ('FDL ','W/m2 ',pverp,'I','Longwave downward flux',phys_decomp) call addfld ('FULC ','W/m2 ',pverp,'I','Longwave clear-sky upward flux',phys_decomp) call addfld ('FDLC ','W/m2 ',pverp,'I','Longwave clear-sky downward flux',phys_decomp) call add_default ('QRL ', 1, ' ') call add_default ('FLNS ', 1, ' ') call add_default ('FLDS ', 1, ' ') call add_default ('FLNT ', 1, ' ') call add_default ('FLUT ', 1, ' ') call add_default ('FLUTC ', 1, ' ') call add_default ('FLNTC ', 1, ' ') call add_default ('FLNSC ', 1, ' ') call add_default ('FLDSC ', 1, ' ') call add_default ('LWCF ', 1, ' ') if (single_column.and.scm_crm_mode) then call add_default ('FUL ', 1, ' ') call add_default ('FULC ', 1, ' ') call add_default ('FDL ', 1, ' ') call add_default ('FDLC ', 1, ' ') endif ! Heating rate needed for d(theta)/dt computation call addfld ('HR ','K/s ',pver, 'A','Heating rate needed for d(theta)/dt computation',phys_decomp) ! (Almost) net radiative flux at surface, does not have lwup. call addfld ('SRFRAD ','W/m2 ',1, 'A','Net radiative flux at surface',phys_decomp) call add_default ('SRFRAD ', 1, ' ') ! Cloud variables call addfld ('CLOUD ','fraction',pver, 'A','Cloud fraction',phys_decomp, sampling_seq='rad_lwsw') call addfld ('CLDTOT ','fraction',1, 'A','Vertically-integrated total cloud',phys_decomp, sampling_seq='rad_lwsw') call addfld ('CLDLOW ','fraction',1, 'A','Vertically-integrated low cloud',phys_decomp, sampling_seq='rad_lwsw') call addfld ('CLDMED ','fraction',1, 'A','Vertically-integrated mid-level cloud',phys_decomp, sampling_seq='rad_lwsw') call addfld ('CLDHGH ','fraction',1, 'A','Vertically-integrated high cloud',phys_decomp, sampling_seq='rad_lwsw') call add_default ('CLOUD ', 1, ' ') call add_default ('CLDTOT ', 1, ' ') call add_default ('CLDLOW ', 1, ' ') call add_default ('CLDMED ', 1, ' ') call add_default ('CLDHGH ', 1, ' ') end subroutine radiation_init !=============================================================================== subroutine radiation_tend(state,ptend,pbuf, & 1,101 cam_out, cam_in, & landfrac,landm,icefrac,snowh, & fsns, fsnt, flns, flnt, & fsds, net_flx) !----------------------------------------------------------------------- ! ! Purpose: ! Driver for radiation computation. ! ! Method: ! Radiation uses cgs units, so conversions must be done from ! model fields to radiation fields. ! ! Revision history: ! May 2004 D.B. Coleman Merge of code from radctl.F90 and parts of tphysbc.F90. ! 2004-08-09 B. Eaton Add pointer variables for constituents. ! 2004-08-24 B. Eaton Access O3 and GHG constituents from chem_get_cnst. ! 2004-08-30 B. Eaton Replace chem_get_cnst by rad_constituent_get. !----------------------------------------------------------------------- use phys_buffer, only: pbuf_size_max, pbuf_fld, pbuf_old_tim_idx, pbuf_get_fld_idx use phys_grid, only: get_rlat_all_p, get_rlon_all_p use param_cldoptics, only: param_cldoptics_calc use physics_types, only: physics_state, physics_ptend use time_manager, only: get_curr_calday use camsrfexch_types,only: surface_state, srfflx_state use cam_history, only: outfld use cloudsimulator, only: doisccp, cloudsimulator_run use radheat, only: radheat_tend use ppgrid use pspect use physconst, only: cpair, stebol use radconstants, only: nlwbands, nswbands use radsw, only: radcswmx use radlw, only: radclwmx use rad_constituents, only: rad_cnst_get_clim_gas, rad_cnst_out use aer_rad_props, only: aer_rad_props_get_clim_sw, aer_rad_props_get_clim_lw use interpolate_data, only: vertinterp use radiation_data, only: output_rad_data ! Arguments real(r8), intent(in) :: landfrac(pcols) ! land fraction real(r8), intent(in) :: landm(pcols) ! land fraction ramp real(r8), intent(in) :: icefrac(pcols) ! land fraction real(r8), intent(in) :: snowh(pcols) ! Snow depth (liquid water equivalent) real(r8), intent(inout) :: fsns(pcols) ! Surface solar absorbed flux real(r8), intent(inout) :: fsnt(pcols) ! Net column abs solar flux at model top real(r8), intent(inout) :: flns(pcols) ! Srf longwave cooling (up-down) flux real(r8), intent(inout) :: flnt(pcols) ! Net outgoing lw flux at model top real(r8), intent(inout) :: fsds(pcols) ! Surface solar down flux real(r8), intent(inout) :: net_flx(pcols) type(physics_state), intent(in), target :: state type(physics_ptend), intent(out) :: ptend type(pbuf_fld), intent(inout) :: pbuf(pbuf_size_max) type(surface_state), intent(inout) :: cam_out type(srfflx_state), intent(in) :: cam_in ! Local variables logical :: dosw, dolw, doabsems integer nmxrgn(pcols) ! Number of maximally overlapped regions real(r8) pmxrgn(pcols,pverp) ! Maximum values of pressure for each ! maximally overlapped region. ! 0->pmxrgn(i,1) is range of pressure for ! 1st region,pmxrgn(i,1)->pmxrgn(i,2) for ! 2nd region, etc real(r8) emis(pcols,pver) ! Cloud longwave emissivity real(r8) :: cldtau(pcols,pver) ! Cloud longwave optical depth real(r8) :: cicewp(pcols,pver) ! in-cloud cloud ice water path real(r8) :: cliqwp(pcols,pver) ! in-cloud cloud liquid water path real(r8) cltot(pcols) ! Diagnostic total cloud cover real(r8) cllow(pcols) ! " low cloud cover real(r8) clmed(pcols) ! " mid cloud cover real(r8) clhgh(pcols) ! " hgh cloud cover real(r8) :: ftem(pcols,pver) ! Temporary workspace for outfld variables integer itim, ifld real(r8), pointer, dimension(:,:) :: rel ! liquid effective drop radius (microns) real(r8), pointer, dimension(:,:) :: rei ! ice effective drop size (microns) real(r8), pointer, dimension(:,:) :: cld ! cloud fraction real(r8), pointer, dimension(:,:) :: concld ! convective cloud fraction real(r8), pointer, dimension(:,:) :: qrs ! shortwave radiative heating rate real(r8), pointer, dimension(:,:) :: qrl ! longwave radiative heating rate real(r8) :: qrsc(pcols,pver) ! clearsky shortwave radiative heating rate real(r8) :: qrlc(pcols,pver) ! clearsky longwave radiative heating rate integer lchnk, ncol real(r8) :: calday ! current calendar day real(r8) :: clat(pcols) ! current latitudes(radians) real(r8) :: clon(pcols) ! current longitudes(radians) real(r8) coszrs(pcols) ! Cosine solar zenith angle logical :: conserve_energy = .true. ! flag to carry (QRS,QRL)*dp across time steps integer i, k ! index integer :: istat real(r8) solin(pcols) ! Solar incident flux real(r8) fsntoa(pcols) ! Net solar flux at TOA real(r8) fsutoa(pcols) ! Upwelling solar flux at TOA real(r8) fsntoac(pcols) ! Clear sky net solar flux at TOA real(r8) fsnirt(pcols) ! Near-IR flux absorbed at toa real(r8) fsnrtc(pcols) ! Clear sky near-IR flux absorbed at toa real(r8) fsnirtsq(pcols) ! Near-IR flux absorbed at toa >= 0.7 microns real(r8) fsntc(pcols) ! Clear sky total column abs solar flux real(r8) fsdtoa(pcols) ! Solar input = Flux Solar Downward Top of Atmosphere real(r8) fsnsc(pcols) ! Clear sky surface abs solar flux real(r8) fsdsc(pcols) ! Clear sky surface downwelling solar flux real(r8) flut(pcols) ! Upward flux at top of model real(r8) lwcf(pcols) ! longwave cloud forcing real(r8) swcf(pcols) ! shortwave cloud forcing real(r8) flutc(pcols) ! Upward Clear Sky flux at top of model real(r8) flntc(pcols) ! Clear sky lw flux at model top real(r8) fldsc(pcols) ! Clear sky down lw flux at srf real(r8) flnsc(pcols) ! Clear sky lw flux at srf (up-down) real(r8) fln200(pcols) ! net longwave flux interpolated to 200 mb real(r8) fln200c(pcols) ! net clearsky longwave flux interpolated to 200 mb real(r8) flds(pcols) ! Srf downwelling longwave flux real(r8) fns(pcols,pverp) ! net shortwave flux real(r8) fcns(pcols,pverp) ! net clear-sky shortwave flux real(r8) fsn200(pcols) ! fns interpolated to 200 mb real(r8) fsn200c(pcols) ! fcns interpolated to 200 mb real(r8) fnl(pcols,pverp) ! net longwave flux real(r8) fcnl(pcols,pverp) ! net clear-sky longwave flux real(r8) pbr(pcols,pver) ! Model mid-level pressures (dynes/cm2) real(r8) pnm(pcols,pverp) ! Model interface pressures (dynes/cm2) real(r8) eccf ! Earth/sun distance factor real(r8) lwupcgs(pcols) ! Upward longwave flux in cgs units real(r8), parameter :: cgs2mks = 1.e-3_r8 real(r8), pointer, dimension(:,:) :: n2o ! nitrous oxide mass mixing ratio real(r8), pointer, dimension(:,:) :: ch4 ! methane mass mixing ratio real(r8), pointer, dimension(:,:) :: cfc11 ! cfc11 mass mixing ratio real(r8), pointer, dimension(:,:) :: cfc12 ! cfc12 mass mixing ratio real(r8), pointer, dimension(:,:) :: o3 ! Ozone mass mixing ratio real(r8), pointer, dimension(:,:) :: o2 ! Oxygen mass mixing ratio real(r8), dimension(pcols) :: o2_col ! column oxygen mmr real(r8), pointer, dimension(:,:) :: co2 ! co2 mass mixing ratio real(r8), dimension(pcols) :: co2_col_mean ! co2 column mean mmr real(r8), pointer, dimension(:,:) :: sp_hum ! specific humidity ! Aerosol shortwave radiative properties real(r8) :: aer_tau (pcols,0:pver,nswbands) ! aerosol extinction optical depth real(r8) :: aer_tau_w (pcols,0:pver,nswbands) ! aerosol single scattering albedo * tau real(r8) :: aer_tau_w_g(pcols,0:pver,nswbands) ! aerosol assymetry parameter * w * tau real(r8) :: aer_tau_w_f(pcols,0:pver,nswbands) ! aerosol forward scattered fraction * w * tau ! Aerosol longwave absorption optical depth real(r8) :: odap_aer(pcols,pver,nlwbands) ! Gathered indicies of day and night columns ! chunk_column_index = IdxDay(daylight_column_index) integer :: Nday ! Number of daylight columns integer :: Nnite ! Number of night columns integer, dimension(pcols) :: IdxDay ! Indicies of daylight coumns integer, dimension(pcols) :: IdxNite ! Indicies of night coumns character(*), parameter :: name = 'radiation_tend' !---------------------------------------------------------------------- lchnk = state%lchnk ncol = state%ncol calday = get_curr_calday() itim = pbuf_old_tim_idx() ifld = pbuf_get_fld_idx('CLD') cld => pbuf(ifld)%fld_ptr(1,1:pcols,1:pver,lchnk,itim) ifld = pbuf_get_fld_idx('CONCLD') concld => pbuf(ifld)%fld_ptr(1,1:pcols,1:pver,lchnk,itim) ifld = pbuf_get_fld_idx('QRS') qrs => pbuf(ifld)%fld_ptr(1,1:pcols,1:pver,lchnk,1) ifld = pbuf_get_fld_idx('QRL') qrl => pbuf(ifld)%fld_ptr(1,1:pcols,1:pver,lchnk,1) ifld = pbuf_get_fld_idx('REL') rel => pbuf(ifld)%fld_ptr(1,1:pcols,1:pver,lchnk, 1) ifld = pbuf_get_fld_idx('REI') rei => pbuf(ifld)%fld_ptr(1,1:pcols,1:pver,lchnk, 1) ! For CRM, make cloud equal to input observations: if (single_column.and.scm_crm_mode.and.have_cld) then do k = 1,pver cld(:ncol,k)= cldobs(k) enddo endif ! Cosine solar zenith angle for current time step call get_rlat_all_p(lchnk, ncol, clat) call get_rlon_all_p(lchnk, ncol, clon) call zenith (calday, clat, clon, coszrs, ncol) call output_rad_data( pbuf, state, cam_in, landm, coszrs ) ! Gather night/day column indices. Nday = 0 Nnite = 0 do i = 1, ncol if ( coszrs(i) > 0.0_r8 ) then Nday = Nday + 1 IdxDay(Nday) = i else Nnite = Nnite + 1 IdxNite(Nnite) = i end if end do dosw = radiation_do('sw') ! do shortwave heating calc this timestep? dolw = radiation_do('lw') ! do longwave heating calc this timestep? doabsems = radiation_do('absems') ! do absorptivity/emissivity calc this timestep? if (dosw .or. dolw) then ! Compute cloud water/ice paths and optical properties for input to radiation call t_startf('cldoptics') call param_cldoptics_calc(state, cld, landfrac, landm,icefrac, & cicewp, cliqwp, emis, cldtau, rel, rei, pmxrgn, nmxrgn, snowh, pbuf) call t_stopf('cldoptics') ! For CRM, make cloud liquid water path equal to input observations if(single_column.and.scm_crm_mode.and.have_clwp)then do k=1,pver cliqwp(:ncol,k) = clwpobs(k) end do endif ! Get specific humidity call rad_cnst_get_clim_gas('H2O', state, pbuf, sp_hum) ! Get ozone mass mixing ratio. call rad_cnst_get_clim_gas('O3', state, pbuf, o3) ! Get CO2 mass mixing ratio and compute column mean values call rad_cnst_get_clim_gas('CO2', state, pbuf, co2) call calc_col_mean(state, co2, co2_col_mean) ! construct cgs unit reps of pmid and pint and get "eccf" - earthsundistancefactor call radinp(ncol, state%pmid, state%pint, pbr, pnm, eccf) ! Solar radiation computation if (dosw) then call t_startf('rad_sw') ! Get Oxygen mass mixing ratio. call rad_cnst_get_clim_gas('O2', state, pbuf, o2) call calc_col_mean(state, o2, o2_col) ! Get aerosol radiative properties. call t_startf('aero_optics_sw') call aer_rad_props_get_clim_sw(state, pbuf, nnite, idxnite, & aer_tau, aer_tau_w, aer_tau_w_g, aer_tau_w_f) call t_stopf('aero_optics_sw') call radcswmx(lchnk, & ncol, pnm, pbr, sp_hum, o3, & o2_col, cld, cicewp, cliqwp, rel, & rei, eccf, coszrs, solin, & cam_in%asdir, cam_in%asdif, cam_in%aldir, cam_in%aldif, nmxrgn, & pmxrgn, qrs, qrsc, fsnt, fsntc, fsdtoa, & fsntoa, fsutoa, fsntoac, fsnirt, fsnrtc, fsnirtsq, & fsns, fsnsc, fsdsc, fsds, cam_out%sols, & cam_out%soll, cam_out%solsd, cam_out%solld, fns, fcns, & Nday, Nnite, IdxDay, IdxNite, co2_col_mean, & aer_tau, aer_tau_w, aer_tau_w_g, aer_tau_w_f ) call t_stopf('rad_sw') ! Output net fluxes at 200 mb call vertinterp(ncol, pcols, pverp, state%pint, 20000._r8, fcns, fsn200c) call vertinterp(ncol, pcols, pverp, state%pint, 20000._r8, fns, fsn200) ! ! Convert units of shortwave fields needed by rest of model from CGS to MKS ! do i=1,ncol solin(i) = solin(i)*cgs2mks fsds(i) = fsds(i)*cgs2mks fsnirt(i)= fsnirt(i)*cgs2mks fsnrtc(i)= fsnrtc(i)*cgs2mks fsnirtsq(i)= fsnirtsq(i)*cgs2mks fsnt(i) = fsnt(i) *cgs2mks fsdtoa(i)= fsdtoa(i) *cgs2mks fsns(i) = fsns(i) *cgs2mks fsntc(i) = fsntc(i)*cgs2mks fsnsc(i) = fsnsc(i)*cgs2mks fsdsc(i) = fsdsc(i)*cgs2mks fsntoa(i)=fsntoa(i)*cgs2mks fsutoa(i)=fsutoa(i)*cgs2mks fsntoac(i)=fsntoac(i)*cgs2mks fsn200(i) = fsn200(i)*cgs2mks fsn200c(i) = fsn200c(i)*cgs2mks swcf(i)=fsntoa(i) - fsntoac(i) end do ftem(:ncol,:pver) = qrs(:ncol,:pver)/cpair ! Dump shortwave radiation information to history buffer (diagnostics) call outfld('QRS ',ftem ,pcols,lchnk) ftem(:ncol,:pver) = qrsc(:ncol,:pver)/cpair call outfld('QRSC ',ftem ,pcols,lchnk) call outfld('SOLIN ',solin ,pcols,lchnk) call outfld('FSDS ',fsds ,pcols,lchnk) call outfld('FSNIRTOA',fsnirt,pcols,lchnk) call outfld('FSNRTOAC',fsnrtc,pcols,lchnk) call outfld('FSNRTOAS',fsnirtsq,pcols,lchnk) call outfld('FSNT ',fsnt ,pcols,lchnk) call outfld('FSDTOA ',fsdtoa,pcols,lchnk) call outfld('FSNS ',fsns ,pcols,lchnk) call outfld('FSNTC ',fsntc ,pcols,lchnk) call outfld('FSNSC ',fsnsc ,pcols,lchnk) call outfld('FSDSC ',fsdsc ,pcols,lchnk) call outfld('FSNTOA ',fsntoa,pcols,lchnk) call outfld('FSUTOA ',fsutoa,pcols,lchnk) call outfld('FSNTOAC ',fsntoac,pcols,lchnk) call outfld('SOLS ',cam_out%sols ,pcols,lchnk) call outfld('SOLL ',cam_out%soll ,pcols,lchnk) call outfld('SOLSD ',cam_out%solsd ,pcols,lchnk) call outfld('SOLLD ',cam_out%solld ,pcols,lchnk) call outfld('FSN200 ',fsn200,pcols,lchnk) call outfld('FSN200C ',fsn200c,pcols,lchnk) call outfld('SWCF ',swcf ,pcols,lchnk) end if ! dosw ! Longwave radiation computation if (dolw) then call t_startf("rad_lw") ! Convert upward longwave flux units to CGS do i=1,ncol lwupcgs(i) = cam_in%lwup(i)*1000._r8 if(single_column.and.scm_crm_mode.and.have_tg) & lwupcgs(i) = 1000*stebol*tground(1)**4 end do ! Get gas phase constituents. call rad_cnst_get_clim_gas('N2O', state, pbuf, n2o) call rad_cnst_get_clim_gas('CH4', state, pbuf, ch4) call rad_cnst_get_clim_gas('CFC11', state, pbuf, cfc11) call rad_cnst_get_clim_gas('CFC12', state, pbuf, cfc12) ! absems requires lw absorption optical depth and transmission through aerosols call t_startf('aero_optics_lw') if (doabsems) call aer_rad_props_get_clim_lw(state, pbuf, odap_aer) call t_stopf('aero_optics_lw') call radclwmx(lchnk, ncol, doabsems, & lwupcgs, state%t, sp_hum, o3, pbr, & pnm, state%lnpmid, state%lnpint, n2o, ch4, & cfc11, cfc12, cld, emis, pmxrgn, & nmxrgn, qrl, qrlc, flns, flnt, flnsc, & flntc, cam_out%flwds, fldsc, flut, flutc, & fnl, fcnl, co2_col_mean, odap_aer) call t_stopf("rad_lw") ! Output fluxes at 200 mb call vertinterp(ncol, pcols, pverp, state%pint, 20000._r8, fnl, fln200) call vertinterp(ncol, pcols, pverp, state%pint, 20000._r8, fcnl, fln200c) ! ! Convert units of longwave fields needed by rest of model from CGS to MKS ! do i=1,ncol flnt(i) = flnt(i)*cgs2mks flut(i) = flut(i)*cgs2mks flutc(i) = flutc(i)*cgs2mks flns(i) = flns(i)*cgs2mks flds(i) = cam_out%flwds(i)*cgs2mks fldsc(i) = fldsc(i)*cgs2mks flntc(i) = flntc(i)*cgs2mks fln200(i) = fln200(i)*cgs2mks fln200c(i) = fln200c(i)*cgs2mks flnsc(i) = flnsc(i)*cgs2mks cam_out%flwds(i) = cam_out%flwds(i)*cgs2mks lwcf(i)=flutc(i) - flut(i) end do ! Dump longwave radiation information to history tape buffer (diagnostics) call outfld('QRL ',qrl (:ncol,:)/cpair,ncol,lchnk) call outfld('QRLC ',qrlc(:ncol,:)/cpair,ncol,lchnk) call outfld('FLNT ',flnt ,pcols,lchnk) call outfld('FLUT ',flut ,pcols,lchnk) call outfld('FLUTC ',flutc ,pcols,lchnk) call outfld('FLNTC ',flntc ,pcols,lchnk) call outfld('FLNS ',flns ,pcols,lchnk) call outfld('FLDS ',flds ,pcols,lchnk) call outfld('FLNSC ',flnsc ,pcols,lchnk) call outfld('FLDSC ',fldsc ,pcols,lchnk) call outfld('LWCF ',lwcf ,pcols,lchnk) call outfld('FLN200 ',fln200,pcols,lchnk) call outfld('FLN200C ',fln200c,pcols,lchnk) end if !dolw ! Output aerosol mmr call rad_cnst_out(state, pbuf) ! Cloud cover diagnostics ! radctl can change pmxrgn and nmxrgn so cldsav needs to follow ! radctl. ! call cldsav (lchnk, ncol, cld, state%pmid, cltot, & cllow, clmed, clhgh, nmxrgn, pmxrgn) ! ! Dump cloud field information to history tape buffer (diagnostics) ! call outfld('CLDTOT ',cltot ,pcols,lchnk) call outfld('CLDLOW ',cllow ,pcols,lchnk) call outfld('CLDMED ',clmed ,pcols,lchnk) call outfld('CLDHGH ',clhgh ,pcols,lchnk) call outfld('CLOUD ',cld ,pcols,lchnk) !This should be written out by stratiform package if (doisccp) then call cloudsimulator_run(state, cam_in%ts, concld, cld, cliqwp, & cicewp, rel, rei, emis, coszrs ) end if else ! if (dosw .or. dolw) then ! convert radiative heating rates from Q*dp to Q for energy conservation if (conserve_energy) then !DIR$ CONCURRENT do k =1 , pver !DIR$ CONCURRENT do i = 1, ncol qrs(i,k) = qrs(i,k)/state%pdel(i,k) qrl(i,k) = qrl(i,k)/state%pdel(i,k) end do end do end if end if ! if (dosw .or. dolw) then ! Compute net radiative heating tendency call radheat_tend(state, pbuf, ptend, qrl, qrs, fsns, & fsnt, flns, flnt, cam_in%asdir, net_flx) ! Compute heating rate for dtheta/dt do k=1,pver do i=1,ncol ftem(i,k) = (qrs(i,k) + qrl(i,k))/cpair * (1.e5_r8/state%pmid(i,k))**cappa end do end do call outfld('HR ',ftem ,pcols ,lchnk ) ! convert radiative heating rates to Q*dp for energy conservation if (conserve_energy) then !DIR$ CONCURRENT do k =1 , pver !DIR$ CONCURRENT do i = 1, ncol qrs(i,k) = qrs(i,k)*state%pdel(i,k) qrl(i,k) = qrl(i,k)*state%pdel(i,k) end do end do end if ! Compute net surface radiative flux for use by surface temperature code. ! Note that units have already been converted to mks in RADCTL. Since ! fsns and flwds are in the buffer, array values will be carried across ! timesteps when the radiation code is not invoked. cam_out%srfrad(:ncol) = fsns(:ncol) + cam_out%flwds(:ncol) call outfld('SRFRAD ',cam_out%srfrad,pcols,lchnk) end subroutine radiation_tend !=============================================================================== subroutine radinp(ncol, pmid, pint, pmidrd, pintrd, eccf) 1,4 !----------------------------------------------------------------------- ! ! Purpose: ! Set latitude and time dependent arrays for input to solar ! and longwave radiation. ! Convert model pressures to cgs. ! ! Author: CCM1, CMS Contact J. Kiehl !----------------------------------------------------------------------- use shr_orb_mod use time_manager, only: get_curr_calday !------------------------------Arguments-------------------------------- ! ! Input arguments ! integer, intent(in) :: ncol ! number of atmospheric columns real(r8), intent(in) :: pmid(pcols,pver) ! Pressure at model mid-levels (pascals) real(r8), intent(in) :: pint(pcols,pverp) ! Pressure at model interfaces (pascals) ! ! Output arguments ! real(r8), intent(out) :: pmidrd(pcols,pver) ! Pressure at mid-levels (dynes/cm*2) real(r8), intent(out) :: pintrd(pcols,pverp) ! Pressure at interfaces (dynes/cm*2) real(r8), intent(out) :: eccf ! Earth-sun distance factor ! !---------------------------Local variables----------------------------- ! integer i ! Longitude loop index integer k ! Vertical loop index real(r8) :: calday ! current calendar day real(r8) :: delta ! Solar declination angle !----------------------------------------------------------------------- ! calday = get_curr_calday() call shr_orb_decl (calday ,eccen ,mvelpp ,lambm0 ,obliqr , & delta ,eccf) ! ! Convert pressure from pascals to dynes/cm2 ! do k=1,pver do i=1,ncol pmidrd(i,k) = pmid(i,k)*10.0_r8 pintrd(i,k) = pint(i,k)*10.0_r8 end do end do do i=1,ncol pintrd(i,pverp) = pint(i,pverp)*10.0_r8 end do end subroutine radinp !=============================================================================== subroutine calc_col_mean(state, mmr_pointer, mean_value) 2,1 !----------------------------------------------------------------------- ! ! Radiation only knows how to work with the column-mean co2 value. ! Compute the column mean. ! !----------------------------------------------------------------------- use cam_logfile, only: iulog type(physics_state), intent(in) :: state real(r8), dimension(:,:), pointer :: mmr_pointer ! mass mixing ratio (lev) real(r8), dimension(pcols), intent(out) :: mean_value ! column mean mmr integer :: i, k, ncol real(r8) :: ptot(pcols) !----------------------------------------------------------------------- ncol = state%ncol mean_value = 0.0_r8 ptot = 0.0_r8 do k=1,pver do i=1,ncol mean_value(i) = mean_value(i) + mmr_pointer(i,k)*state%pdeldry(i,k) ptot(i) = ptot(i) + state%pdeldry(i,k) end do end do do i=1,ncol mean_value(i) = mean_value(i) / ptot(i) end do end subroutine calc_col_mean !=============================================================================== end module radiation