diff --git a/.gitignore b/.gitignore index a3997f2a..25472c52 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,8 @@ buildnmlc test/include/*.mod test/include/*.o test/unit/tmp +test/system/*.log +test/system/cime-tests.o* # Ignore editor temporaries and backups *.swp diff --git a/Externals.cfg b/Externals.cfg index 5a9544c6..ad6907e6 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -1,5 +1,5 @@ [ccs_config] -tag = ccs_config_cesm0.0.78 +tag = ccs_config_cesm0.0.106 protocol = git repo_url = https://github.com/ESMCI/ccs_config_cesm local_path = ccs_config @@ -13,7 +13,7 @@ local_path = components/cice5 required = True [cice6] -tag = cesm_cice6_4_1_10 +tag = cesm_cice6_5_0_7 protocol = git repo_url = https://github.com/ESCOMP/CESM_CICE local_path = components/cice @@ -21,14 +21,14 @@ externals = Externals.cfg required = True [cmeps] -tag = cmeps0.14.39 +tag = cmeps0.14.60 protocol = git repo_url = https://github.com/ESCOMP/CMEPS.git local_path = components/cmeps required = True [cdeps] -tag = cdeps1.0.21 +tag = cdeps1.0.33 protocol = git repo_url = https://github.com/ESCOMP/CDEPS.git local_path = components/cdeps @@ -36,14 +36,14 @@ externals = Externals_CDEPS.cfg required = True [cpl7] -tag = cpl77.0.6 +tag = cpl77.0.8 protocol = git repo_url = https://github.com/ESCOMP/CESM_CPL7andDataComps local_path = components/cpl7 required = True [share] -tag = share1.0.17 +tag = share1.0.18 protocol = git repo_url = https://github.com/ESCOMP/CESM_share local_path = share @@ -64,14 +64,14 @@ local_path = libraries/parallelio required = True [cime] -tag = cime6.0.175 +tag = cime6.0.236_httpsbranch01 protocol = git repo_url = https://github.com/ESMCI/cime local_path = cime required = True [cism] -tag = cismwrap_2_1_96 +tag = cismwrap_2_1_100 protocol = git repo_url = https://github.com/ESCOMP/CISM-wrapper local_path = components/cism @@ -79,7 +79,7 @@ externals = Externals_CISM.cfg required = True [clm] -tag = ctsm5.1.dev139 +tag = ctsm5.2.005 protocol = git repo_url = https://github.com/ESCOMP/CTSM local_path = components/clm @@ -87,8 +87,7 @@ externals = Externals_CLM.cfg required = True [fms] -# Older tag than CESM as there is a compilation error mismatch -tag = fi_20211011 +tag = fi_230818 protocol = git repo_url = https://github.com/ESCOMP/FMS_interface local_path = libraries/FMS @@ -96,14 +95,14 @@ externals = Externals_FMS.cfg required = True [mosart] -tag = mosart1_0_48 +tag = mosart1_0_49 protocol = git repo_url = https://github.com/ESCOMP/MOSART local_path = components/mosart required = True [rtm] -tag = rtm1_0_78 +tag = rtm1_0_79 protocol = git repo_url = https://github.com/ESCOMP/RTM local_path = components/rtm diff --git a/Externals_CAM.cfg b/Externals_CAM.cfg index 0968b6da..43c64dcc 100644 --- a/Externals_CAM.cfg +++ b/Externals_CAM.cfg @@ -17,7 +17,7 @@ required = True local_path = src/physics/ncar_ccpp protocol = git repo_url = https://github.com/ESCOMP/atmospheric_physics -tag = atmos_phys0_02_003 +tag = atmos_phys0_02_006 required = True [externals_description] diff --git a/src/control/cam_comp.F90 b/src/control/cam_comp.F90 index a36f4cca..85edc36c 100644 --- a/src/control/cam_comp.F90 +++ b/src/control/cam_comp.F90 @@ -66,7 +66,8 @@ module cam_comp subroutine cam_init(caseid, ctitle, model_doi_url, & initial_run_in, restart_run_in, branch_run_in, & - calendar, brnch_retain_casename, aqua_planet, & + post_assim_in, calendar, & + brnch_retain_casename, aqua_planet, & single_column, scmlat, scmlon, & eccen, obliqr, lambm0, mvelpp, & perpetual_run, perpetual_ymd, & @@ -105,6 +106,7 @@ subroutine cam_init(caseid, ctitle, model_doi_url, & logical, intent(in) :: initial_run_in ! is inital run? logical, intent(in) :: restart_run_in ! is restart run? logical, intent(in) :: branch_run_in ! is branch run? + logical, intent(in) :: post_assim_in ! true => resume mode character(len=cs), intent(in) :: calendar ! Calendar type ! brnch_retain_casename is a flag to allow a branch to use the same ! caseid as the run being branched from. @@ -155,6 +157,7 @@ subroutine cam_init(caseid, ctitle, model_doi_url, & initial_run_in=initial_run_in, & restart_run_in=restart_run_in, & branch_run_in=branch_run_in, & + post_assim_in=post_assim_in, & aqua_planet_in=aqua_planet, & brnch_retain_casename_in=brnch_retain_casename) diff --git a/src/control/cam_control_mod.F90 b/src/control/cam_control_mod.F90 index 51b860b3..11057198 100644 --- a/src/control/cam_control_mod.F90 +++ b/src/control/cam_control_mod.F90 @@ -27,19 +27,21 @@ module cam_control_mod logical, protected :: initial_run ! startup mode which only requires a minimal initial file logical, protected :: restart_run ! continue a previous run; requires a restart file logical, protected :: branch_run ! branch from a previous run; requires a restart file + logical, protected :: post_assim ! We are resuming after a pause logical, protected :: adiabatic ! true => no physics logical, protected :: ideal_phys ! true => run Held-Suarez (1994) physics logical, protected :: kessler_phys ! true => run Kessler physics logical, protected :: tj2016_phys ! true => run tj2016 physics + logical, protected :: grayrad_phys ! true => run gray radiation (frierson) physics logical, protected :: simple_phys ! true => adiabatic or ideal_phys or kessler_phys - ! or tj2016 + ! or tj2016 or grayrad logical, protected :: aqua_planet ! Flag to run model in "aqua planet" mode logical, protected :: moist_physics ! true => moist physics enabled, i.e., - ! (.not. ideal_phys) .and. (.not. adiabatic) + ! (.not. ideal_phys) .and. (.not. adiabatic) logical, protected :: brnch_retain_casename ! true => branch run may use same caseid as - ! the run being branched from + ! the run being branched from real(r8), protected :: eccen ! Earth's eccentricity factor (unitless) (typically 0 to 0.1) real(r8), protected :: obliqr ! Earth's obliquity in radians @@ -53,13 +55,15 @@ module cam_control_mod !============================================================================== subroutine cam_ctrl_init(caseid_in, ctitle_in, initial_run_in, & - restart_run_in, branch_run_in, aqua_planet_in, brnch_retain_casename_in) + restart_run_in, branch_run_in, post_assim_in, & + aqua_planet_in, brnch_retain_casename_in) character(len=cl), intent(in) :: caseid_in ! case ID character(len=cl), intent(in) :: ctitle_in ! case title logical, intent(in) :: initial_run_in ! true => inital run logical, intent(in) :: restart_run_in ! true => restart run logical, intent(in) :: branch_run_in ! true => branch run + logical, intent(in) :: post_assim_in ! true => resume mode logical, intent(in) :: aqua_planet_in ! Flag to run model in "aqua planet" mode logical, intent(in) :: brnch_retain_casename_in ! Flag to allow a branch to use the same ! caseid as the run being branched from. @@ -73,6 +77,7 @@ subroutine cam_ctrl_init(caseid_in, ctitle_in, initial_run_in, & initial_run = initial_run_in restart_run = restart_run_in branch_run = branch_run_in + post_assim = post_assim_in aqua_planet = aqua_planet_in @@ -87,6 +92,8 @@ subroutine cam_ctrl_init(caseid_in, ctitle_in, initial_run_in, & write(iulog,*) ' Restart of an earlier run' else if (branch_run) then write(iulog,*) ' Branch of an earlier run' + else if (post_assim) then + write(iulog,*) ' DART run using CAM initial mode' else write(iulog,*) ' Initial run' end if @@ -137,11 +144,12 @@ subroutine cam_ctrl_set_physics_type() suite_name = suite_names(1) adiabatic = trim(suite_name) == 'adiabatic' - ideal_phys = trim(suite_name) == 'held_suarez' + ideal_phys = trim(suite_name) == 'held_suarez_1994' kessler_phys = trim(suite_name) == 'kessler' tj2016_phys = trim(suite_name) == 'tj2016' + grayrad_phys = trim(suite_name) == 'grayrad' - simple_phys = adiabatic .or. ideal_phys .or. kessler_phys .or. tj2016_phys + simple_phys = adiabatic .or. ideal_phys .or. kessler_phys .or. tj2016_phys .or. grayrad_phys moist_physics = .not. (adiabatic .or. ideal_phys) @@ -159,6 +167,8 @@ subroutine cam_ctrl_set_physics_type() write(iulog,*) 'Run model with Kessler warm-rain physics forcing' else if (tj2016_phys) then write(iulog,*) 'Run model with Thatcher-Jablonowski (2016) physics forcing (moist Held-Suarez)' + else if (grayrad_phys) then + write(iulog,*) 'Run model with Frierson (2006) gray radiation physics' end if end if diff --git a/src/control/cam_logfile.F90 b/src/control/cam_logfile.F90 index 8c25d10c..0316297b 100644 --- a/src/control/cam_logfile.F90 +++ b/src/control/cam_logfile.F90 @@ -59,7 +59,7 @@ subroutine cam_set_log_unit(unit_num) integer, intent(in) :: unit_num - ! Change iulog to unit_num on this PE or log a waring + ! Change iulog to unit_num on this PE or log a warning ! The log unit number can be set at most once per run if (iulog_set) then write(iulog, *) 'cam_set_log_unit: Cannot change log unit during run' diff --git a/src/cpl/mct/atm_comp_mct.F90 b/src/cpl/mct/atm_comp_mct.F90 deleted file mode 100644 index 43d7df99..00000000 --- a/src/cpl/mct/atm_comp_mct.F90 +++ /dev/null @@ -1,920 +0,0 @@ -module atm_comp_mct - - use shr_kind_mod, only: r8 => shr_kind_r8 - use shr_kind_mod, only: cs=>shr_kind_cs, cl=>shr_kind_cl - use shr_file_mod, only: shr_file_getunit, shr_file_setLogUnit - use shr_file_mod, only: shr_file_setLogLevel, shr_file_getLogLevel - use shr_file_mod, only: shr_file_getLogUnit, shr_file_setIO - use shr_sys_mod, only: shr_sys_flush - use shr_flds_mod, only: shr_flds_dom_coord, shr_flds_dom_other - use seq_flds_mod, only: seq_flds_x2a_fields, seq_flds_a2x_fields - use pio, only: file_desc_t, io_desc_t, var_desc_t, pio_double - use pio, only: pio_def_dim, pio_put_att, pio_enddef - use pio, only: pio_read_darray, pio_freedecomp - use pio, only: pio_closefile, pio_write_darray, pio_def_var - use pio, only: pio_inq_varid, pio_noerr, pio_bcast_error - use pio, only: pio_internal_error, pio_seterrorhandling - use pio, only: PIO_OFFSET_KIND - use mct_mod, only: mct_aVect, mct_aVect, mct_gGrid - use mct_mod, only: mct_aVect_zero - use mct_mod, only: mct_aVect_getRList, mct_string_toChar - use mct_mod, only: mct_string, mct_string_clean - use mct_mod, only: mct_gsMap, mct_gsMap_lsize, mct_aVect_nRattr - use mct_mod, only: mct_gGrid_init, mct_gsMap_orderedPoints - use mct_mod, only: mct_gGrid_importIAttr, mct_gGrid_importRAttr - use mct_mod, only: mct_gsmap_orderedpoints, mct_gsMap_init - use seq_comm_mct, only: seq_comm_inst, seq_comm_name, seq_comm_suffix - use seq_comm_mct, only: num_inst_atm - use seq_cdata_mod, only: seq_cdata, seq_cdata_setptrs - use seq_infodata_mod, only: seq_infodata_type - use seq_infodata_mod, only: seq_infodata_GetData, seq_infodata_PutData - use esmf, only: ESMF_Clock - use seq_timemgr_mod, only: seq_timemgr_EClockGetData - use seq_timemgr_mod, only: seq_timemgr_EClockDateInSync - use seq_timemgr_mod, only: seq_timemgr_StopAlarmIsOn - use seq_timemgr_mod, only: seq_timemgr_RestartAlarmIsOn - use atm_import_export, only: atm_import, atm_export - use cam_comp, only: cam_init, cam_run1, cam_run2, cam_run3 - use cam_comp, only: cam_run4, cam_final - use cam_instance, only: cam_instance_init, inst_suffix, inst_index - use cam_control_mod, only: cam_ctrl_set_orbit -! use radiation, only: radiation_nextsw_cday - use camsrfexch, only: cam_out_t, cam_in_t - use cam_initfiles, only: cam_initfiles_get_caseid - use cam_initfiles, only: cam_initfiles_get_restdir - use cam_abortutils, only: endrun - use filenames, only: interpret_filename_spec - use spmd_utils, only: spmd_init, masterproc, iam - use time_manager, only: get_curr_calday, advance_timestep - use time_manager, only: get_curr_date, get_nstep, get_step_size - use ioFileMod, only: cam_get_file - use perf_mod, only: t_startf, t_stopf - use cam_logfile, only: cam_set_log_unit, iulog - use cam_cpl_indices ! Temporary exception to naked use - - implicit none - private - - !-------------------------------------------------------------------------- - ! Public interfaces - !-------------------------------------------------------------------------- - - public :: atm_init_mct - public :: atm_run_mct - public :: atm_final_mct - - !-------------------------------------------------------------------------- - ! Private interfaces - !-------------------------------------------------------------------------- - - private :: atm_setgsmap_mct - private :: atm_domain_mct - private :: atm_read_srfrest_mct - private :: atm_write_srfrest_mct - - !-------------------------------------------------------------------------- - ! Private data - !-------------------------------------------------------------------------- - - type(cam_in_t), pointer :: cam_in => NULL() - type(cam_out_t), pointer :: cam_out => NULL() - - ! rsfilename_spec_cam: Filename specifier for restart surface file - character(len=cl) :: rsfilename_spec_cam - - integer, pointer :: dof(:) => NULL() ! PIO decomp 4 restarts - type(seq_infodata_type), pointer :: infodata => NULL() - - logical :: dart_mode = .false. - -!=========================================================================== -CONTAINS -!=========================================================================== - - subroutine atm_init_mct(EClock, cdata_a, x2a_a, a2x_a, NLFilename) - use physics_grid, only: get_grid_dims - - !----------------------------------------------------------------------- - ! - ! Arguments - ! - type(ESMF_Clock), intent(inout) :: EClock - type(seq_cdata), intent(inout) :: cdata_a - type(mct_aVect), intent(inout) :: x2a_a - type(mct_aVect), intent(inout) :: a2x_a - character(len=*), optional, intent(in) :: NLFilename ! Namelist - ! - ! Locals - ! - type(mct_gsMap), pointer :: gsMap_atm - type(mct_gGrid), pointer :: dom_a - integer :: ATMID - integer :: mpicom_atm - integer :: lsize - logical :: first_time = .true. - logical :: exists - integer :: shrlogunit ! save values, restore on return - integer :: shrloglev ! save values, restore on return - character(len=cs) :: start_type ! infodata start type - character(len=cl) :: caseid ! case ID - character(len=cl) :: ctitle ! case title - character(len=cl) :: model_doi_url ! DOI for CESM model run - character(len=cs) :: calendar ! Calendar type - logical :: aqua_planet ! Flag to run model in "aqua planet" mode - ! brnch_retain_casename: branch run may use same caseid as the run being branched from - logical :: brnch_retain_casename - logical :: single_column - real(r8) :: scmlat - real(r8) :: scmlon - real(r8) :: eccen - real(r8) :: obliqr - real(r8) :: lambm0 - real(r8) :: mvelpp - logical :: perpetual_run ! If in perpetual mode or not - integer :: perpetual_ymd ! Perpetual date (YYYYMMDD) - - real(r8) :: nextsw_cday ! calendar of next atm shortwave - integer :: stepno ! time step - integer :: dtime ! time step increment (sec) - integer :: atm_cpl_dt ! driver atm coupling time step - integer :: nstep ! CAM nstep - real(r8) :: caldayp1 ! CAM calendar day for for next cam time step - integer :: start_ymd ! Start date (YYYYMMDD) - integer :: start_tod ! Start time of day (sec) - integer :: curr_ymd ! Start date (YYYYMMDD) - integer :: curr_tod ! Start time of day (sec) - integer :: stop_ymd ! Stop date (YYYYMMDD) - integer :: stop_tod ! Stop time of day (sec) - integer :: ref_ymd ! Reference date (YYYYMMDD) - integer :: ref_tod ! Reference time of day (sec) - logical :: initial_run ! startup mode which only requires a minimal initial file - logical :: restart_run ! continue a previous run; requires a restart file - logical :: branch_run ! branch from a previous run; requires a restart file - integer :: lbnum - character(cs) :: inst_name - integer :: inst_index - character(cs) :: inst_suffix - integer :: hdim1_d, hdim2_d ! grid dimensions - character(len=*), parameter :: subname = 'atm_init_mct' - ! data structure, If 1D data structure, then hdim2_d == 1. - !----------------------------------------------------------------------- - ! - ! Determine cdata points - ! - call seq_cdata_setptrs(cdata_a, ID=ATMID, mpicom=mpicom_atm, & - gsMap=gsMap_atm, dom=dom_a, infodata=infodata, & - post_assimilation=dart_mode) - - if (first_time) then - - ! determine instance information - inst_name = seq_comm_name(ATMID) - inst_index = seq_comm_inst(ATMID) - inst_suffix = seq_comm_suffix(ATMID) - call cam_instance_init(ATMID, inst_name, inst_index, inst_suffix) - - ! Set filename specifier for restart surface file - ! (%c=caseid, $y=year, $m=month, $d=day, $s=seconds in day) - rsfilename_spec_cam = '%c.cam'//trim(inst_suffix)//'.rs.%y-%m-%d-%s.nc' - - ! Determine attribute vector indices - call cam_cpl_indices_set() - - ! Initialize atm use of MPI - call spmd_init(mpicom_atm) - -#if (defined _MEMTRACE) - if(masterproc) then - lbnum = 1 - call memmon_dump_fort('memmon.out', 'atm_init_mct:start::', lbnum) - end if -#endif - - ! Redirect share output to cam log - - if (masterproc) then - inquire(file='atm_modelio.nml'//trim(inst_suffix), exist=exists) - if (exists) then - call cam_set_log_unit(shr_file_getUnit()) - call shr_file_setIO('atm_modelio.nml'//trim(inst_suffix), iulog) - end if - - write(iulog, *) "CAM atmosphere model initialization" - if (dart_mode) then - write(iulog, *) "***DART mode ON***" - end if - end if - - call shr_file_getLogUnit (shrlogunit) - call shr_file_getLogLevel(shrloglev) - call shr_file_setLogUnit (iulog) - ! - ! Get data from infodata object - ! - ! TODO: the perpetual_run does not work for nuopc since nextsw_cday is - ! not being set correctly - ! FOR now will debug without support for perpetual until this - ! can be resolved - perpetual_run = .false. - - call seq_infodata_GetData(infodata, & - case_name=caseid, case_desc=ctitle, & - model_doi_url=model_doi_url, & - start_type=start_type, aqua_planet=aqua_planet, & - brnch_retain_casename=brnch_retain_casename, & - single_column=single_column, scmlat=scmlat, scmlon=scmlon, & - orb_eccen=eccen, orb_mvelpp=mvelpp, orb_lambm0=lambm0, & - orb_obliqr=obliqr, & - perpetual=perpetual_run, perpetual_ymd=perpetual_ymd) - - ! set the run type - initial_run = .false. - restart_run = .false. - branch_run = .false. - if (trim(start_type) == 'startup') then - initial_run = .true. - else if (trim(start_type) == 'continue') then - restart_run = .true. - else if (trim(start_type) == 'branch') then - branch_run = .true. - else - call endrun(subname//': ERROR: unknown start_type, '// trim(start_type)) - end if - - ! DART always starts up as an initial run. - if (dart_mode) then - initial_run = .true. - restart_run = .false. - branch_run = .false. - end if - - ! Extract info from the eclock passed from coupler to initialize - ! the local time manager - - call seq_timemgr_EClockGetData(Eclock, & - start_ymd=start_ymd, start_tod=start_tod, & - ref_ymd=ref_ymd, ref_tod=ref_tod, & - stop_ymd=stop_ymd, stop_tod=stop_tod, & - curr_ymd=curr_ymd, curr_tod=curr_tod, & - dtime=dtime, calendar=calendar) - - ! Initialize CAM, allocate cam_in and cam_out and determine - ! atm decomposition (needed to initialize gsmap) - ! for an initial run, cam_in and cam_out are allocated in cam_init - ! for a restart/branch run, cam_in and cam_out are allocated in restart - - call cam_init( & - caseid=caseid, & - ctitle=ctitle, & - model_doi_url=model_doi_url, & - initial_run_in=initial_run, & - restart_run_in=restart_run, & - branch_run_in=branch_run, & - calendar=calendar, & - brnch_retain_casename=brnch_retain_casename, & - aqua_planet=aqua_planet, & - single_column=single_column, & - scmlat=scmlat, & - scmlon=scmlon, & - eccen=eccen, & - obliqr=obliqr, & - lambm0=lambm0, & - mvelpp=mvelpp, & - perpetual_run=perpetual_run, & - perpetual_ymd=perpetual_ymd, & - dtime=dtime, & - start_ymd=start_ymd, & - start_tod=start_tod, & - ref_ymd=ref_ymd, & - ref_tod=ref_tod, & - stop_ymd=stop_ymd, & - stop_tod=stop_tod, & - curr_ymd=curr_ymd, & - curr_tod=curr_tod, & - cam_out=cam_out, & - cam_in=cam_in) - ! - ! Initialize MCT gsMap, domain and attribute vectors (and dof) - ! - call atm_SetgsMap_mct(mpicom_atm, ATMID, gsMap_atm) - lsize = mct_gsMap_lsize(gsMap_atm, mpicom_atm) - - ! Set dof (module variable, needed for pio for restarts) - call mct_gsmap_orderedpoints(gsmap_atm, iam, dof) - ! - ! Initialize MCT domain - ! - call atm_domain_mct(lsize, gsMap_atm, dom_a) - ! - ! Initialize MCT attribute vectors - ! - call mct_aVect_init(a2x_a, rList=seq_flds_a2x_fields, lsize=lsize) - call mct_aVect_zero(a2x_a) - - call mct_aVect_init(x2a_a, rList=seq_flds_x2a_fields, lsize=lsize) - call mct_aVect_zero(x2a_a) - ! - ! Create initial atm export state - ! - call atm_export(cam_out, a2x_a%rattr) - ! - ! Set flag to specify that an extra albedo calculation is - ! to be done (i.e. specify active) - ! - call seq_infodata_PutData(infodata, atm_prognostic=.true.) - call get_grid_dims(hdim1_d, hdim2_d) - call seq_infodata_PutData(infodata, atm_nx=hdim1_d, atm_ny=hdim2_d) - - ! Set flag to indicate that CAM will provide carbon and dust - ! deposition fluxes. - ! This is now hardcoded to .true. since the ability of CICE to - ! read these fluxes from a file has been removed. - call seq_infodata_PutData(infodata, atm_aero=.true.) - - ! - ! Set time step of radiation computation as the current calday - ! This will only be used on the first timestep of an initial run - ! - if (initial_run) then - nextsw_cday = get_curr_calday() - call seq_infodata_PutData(infodata, nextsw_cday=nextsw_cday) - end if - - ! End redirection of share output to cam log - - call shr_file_setLogUnit (shrlogunit) - call shr_file_setLogLevel(shrloglev) - - first_time = .false. - - else - - ! For initial run, run cam radiation/clouds and return - ! For restart run, read restart x2a_a - ! Note - a2x_a is computed upon the completion of the previous run - cam_run1 is called - ! only for the purposes of finishing the flux averaged calculation to compute a2x_a - ! Note - cam_run1 is called on restart only to have cam internal state consistent with the - ! a2x_a state sent to the coupler - - ! Redirect share output to cam log - - call shr_file_getLogUnit (shrlogunit) - call shr_file_getLogLevel(shrloglev) - call shr_file_setLogUnit (iulog) - - call seq_timemgr_EClockGetData(EClock, StepNo=StepNo) - if (StepNo == 0) then - call atm_import(x2a_a%rattr, cam_in) - call cam_run1 (cam_in, cam_out) - call atm_export(cam_out, a2x_a%rattr) - else - call atm_read_srfrest_mct(EClock, x2a_a, a2x_a) - call atm_import(x2a_a%rattr, cam_in, restart_init=.true.) - call cam_run1 (cam_in, cam_out) - end if - - ! Compute time of next radiation computation, like in run method - ! for exact restart - call seq_timemgr_EClockGetData(Eclock, dtime=atm_cpl_dt) - dtime = get_step_size() - nstep = get_nstep() -!!XXgoldyXX: v figure out what to do with radiation -#if 0 - if (nstep < 1 .or. dtime < atm_cpl_dt) then - nextsw_cday = radiation_nextsw_cday() - else if (dtime == atm_cpl_dt) then - caldayp1 = get_curr_calday(offset=int(dtime)) - nextsw_cday = radiation_nextsw_cday() - if (caldayp1 /= nextsw_cday) nextsw_cday = -1._r8 - else - call endrun(subname//': dtime must be less than or equal to atm_cpl_dt') - end if -#endif -!!XXgoldyXX: ^ figure out what to do with radiation - call seq_infodata_PutData(infodata, nextsw_cday=nextsw_cday) - - ! End redirection of share output to cam log - - call shr_file_setLogUnit (shrlogunit) - call shr_file_setLogLevel(shrloglev) - - end if - -#if (defined _MEMTRACE) - if(masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out', 'atm_init_mct:end::', lbnum) - call memmon_reset_addr() - endif -#endif - - call shr_sys_flush(iulog) - - end subroutine atm_init_mct - - !=========================================================================== - - subroutine atm_run_mct(EClock, cdata_a, x2a_a, a2x_a) - - !----------------------------------------------------------------------- - ! - ! Arguments - ! - type(ESMF_Clock), intent(inout) :: EClock - type(seq_cdata), intent(inout) :: cdata_a - type(mct_aVect), intent(inout) :: x2a_a - type(mct_aVect), intent(inout) :: a2x_a - ! - ! Local variables - ! - integer :: shrlogunit, shrloglev ! save values, restore on exit - - real(r8) :: eccen - real(r8) :: obliqr - real(r8) :: lambm0 - real(r8) :: mvelpp - - logical :: dosend ! true => send data back to driver - integer :: dtime ! time step increment (sec) - integer :: atm_cpl_dt ! driver atm coupling time step - integer :: ymd_sync ! Sync date (YYYYMMDD) - integer :: yr_sync ! Sync current year - integer :: mon_sync ! Sync current month - integer :: day_sync ! Sync current day - integer :: tod_sync ! Sync current time of day (sec) - integer :: ymd ! CAM current date (YYYYMMDD) - integer :: yr ! CAM current year - integer :: mon ! CAM current month - integer :: day ! CAM current day - integer :: tod ! CAM current time of day (sec) - - real(r8):: caldayp1 ! CAM calendar day for for next cam time step - real(r8):: nextsw_cday ! calendar of next atm shortwave - logical :: rstwr ! .true. ==> write restart file before returning - logical :: nlend ! Flag signaling last time-step - logical :: rstwr_sync ! .true. ==> write restart file before returning - logical :: nlend_sync ! Flag signaling last time-step - logical :: first_time = .true. - integer :: lbnum - character(len=*), parameter :: subname="atm_run_mct" - !----------------------------------------------------------------------- - -#if (defined _MEMTRACE) - if(masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out', SubName //':start::', lbnum) - endif -#endif - - ! Redirect share output to cam log - - call shr_file_getLogUnit (shrlogunit) - call shr_file_getLogLevel(shrloglev) - call shr_file_setLogUnit (iulog) - - ! Note that sync clock time should match cam time at end of - ! time step/loop not beginning - call seq_timemgr_EClockGetData(EClock, curr_ymd=ymd_sync, & - curr_tod=tod_sync, curr_yr=yr_sync, curr_mon=mon_sync, & - curr_day=day_sync) - - nlend_sync = seq_timemgr_StopAlarmIsOn(EClock) - rstwr_sync = seq_timemgr_RestartAlarmIsOn(EClock) - - ! load orbital parameters - call seq_infodata_GetData(infodata, orb_eccen=eccen, orb_mvelpp=mvelpp, & - orb_lambm0=lambm0, orb_obliqr=obliqr) - call cam_ctrl_set_orbit(eccen, obliqr, lambm0, mvelpp) - - ! Map input from mct to cam data structure - - call t_startf ('CAM_import') - call atm_import(x2a_a%rattr, cam_in) - call t_stopf ('CAM_import') - - ! Cycle over all time steps in the atm coupling interval - - dosend = .false. - do while (.not. dosend) - - ! Determine if dosend - ! When time is not updated at the beginning of the loop - - ! then return only if are in sync with clock before time is updated - call get_curr_date(yr, mon, day, tod) - ymd = yr*10000 + mon*100 + day - tod = tod - dosend = (seq_timemgr_EClockDateInSync(EClock, ymd, tod)) - - ! Determine if time to write cam restart and stop - - rstwr = .false. - if (rstwr_sync .and. dosend) rstwr = .true. - nlend = .false. - if (nlend_sync .and. dosend) nlend = .true. - - ! Run CAM (run2, run3, run4) - - call t_startf ('CAM_run2') - call cam_run2(cam_out, cam_in) - call t_stopf ('CAM_run2') - - call t_startf ('CAM_run3') - call cam_run3(cam_out) - call t_stopf ('CAM_run3') - - call t_startf ('CAM_run4') - call cam_run4(cam_out, cam_in, rstwr, nlend, yr_spec=yr_sync, & - mon_spec=mon_sync, day_spec=day_sync, sec_spec=tod_sync) - call t_stopf ('CAM_run4') - - ! Advance cam time step - - call t_startf ('CAM_adv_timestep') - call advance_timestep() - call t_stopf ('CAM_adv_timestep') - - ! Run cam radiation/clouds (run1) - - call t_startf ('CAM_run1') - call cam_run1 (cam_in, cam_out) - call t_stopf ('CAM_run1') - - ! Map output from cam to mct data structures - - call t_startf ('CAM_export') - call atm_export(cam_out, a2x_a%rattr) - call t_stopf ('CAM_export') - - end do - - ! Get time of next radiation calculation - albedos will need to be - ! calculated by each surface model at this time - - call seq_timemgr_EClockGetData(Eclock, dtime=atm_cpl_dt) - dtime = get_step_size() -!!XXgoldyXX: v figure out what to do with radiation -#if 0 - if (dtime < atm_cpl_dt) then - nextsw_cday = radiation_nextsw_cday() - else if (dtime == atm_cpl_dt) then - caldayp1 = get_curr_calday(offset=int(dtime)) - nextsw_cday = radiation_nextsw_cday() - if (caldayp1 /= nextsw_cday) nextsw_cday = -1._r8 - else - call endrun(subname//': dtime must be less than or equal to atm_cpl_dt') - end if -#endif -!!XXgoldyXX: ^ figure out what to do with radiation - - call seq_infodata_PutData(infodata, nextsw_cday=nextsw_cday) - - ! Write merged surface data restart file if appropriate - - if (rstwr_sync) then - call atm_write_srfrest_mct(x2a_a, a2x_a, yr_spec=yr_sync, & - mon_spec=mon_sync, day_spec=day_sync, sec_spec=tod_sync) - end if - - ! Check for consistency of internal cam clock with master sync clock - - dtime = get_step_size() - call get_curr_date(yr, mon, day, tod, offset=-dtime) - ymd = yr*10000 + mon*100 + day - tod = tod - if (.not. seq_timemgr_EClockDateInSync(EClock, ymd, tod))then - call seq_timemgr_EClockGetData(EClock, curr_ymd=ymd_sync, & - curr_tod=tod_sync) - write(iulog, *)' cam ymd=', ymd, ' cam tod= ', tod - write(iulog, *)'sync ymd=', ymd_sync, ' sync tod= ', tod_sync - call endrun(subname//': CAM clock is not in sync with master Sync Clock') - end if - - ! End redirection of share output to cam log - - call shr_file_setLogUnit (shrlogunit) - call shr_file_setLogLevel(shrloglev) - -#if (defined _MEMTRACE) - if(masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out', SubName //':end::', lbnum) - call memmon_reset_addr() - endif -#endif - - end subroutine atm_run_mct - - !=========================================================================== - - subroutine atm_final_mct(EClock, cdata_a, x2a_a, a2x_a) - - type(ESMF_Clock), intent(inout) :: EClock - type(seq_cdata), intent(inout) :: cdata_a - type(mct_aVect), intent(inout) :: x2a_a - type(mct_aVect), intent(inout) :: a2x_a - - call cam_final(cam_out, cam_in) - - end subroutine atm_final_mct - - !=========================================================================== - - subroutine atm_SetgsMap_mct(mpicom_atm, ATMID, GSMap_atm) - use physics_grid, only: columns_on_task, num_global_phys_cols - use physics_grid, only: global_index_p - - !------------------------------------------------------------------- - ! - ! Arguments - ! - integer, intent(in) :: mpicom_atm - integer, intent(in) :: ATMID - type(mct_gsMap), intent(out) :: GSMap_atm - ! - ! Local variables - ! - integer, allocatable :: gindex(:) - integer :: index - integer :: ierr ! error status - !------------------------------------------------------------------- - - ! Build the atmosphere grid numbering for MCT - ! Determine global seg map - allocate(gindex(columns_on_task)) - - do index = 1, columns_on_task - gindex(index) = global_index_p(index) - end do - - call mct_gsMap_init(gsMap_atm, gindex, mpicom_atm, ATMID, & - columns_on_task, num_global_phys_cols) - - deallocate(gindex) - - end subroutine atm_SetgsMap_mct - - !=========================================================================== - - subroutine atm_domain_mct(lsize, gsMap_a, dom_a) - use physics_grid, only: columns_on_task - use physics_grid, only: get_dlat_p, get_dlon_p, get_area_p - - !------------------------------------------------------------------- - ! - ! Arguments - ! - integer, intent(in) :: lsize - type(mct_gsMap), intent(in) :: gsMap_a - type(mct_ggrid), intent(inout) :: dom_a - ! - ! Local Variables - ! - integer :: index - real(r8), pointer :: data(:) ! temporary - integer, pointer :: idata(:) ! temporary - !------------------------------------------------------------------- - ! - ! Initialize mct atm domain - ! - call mct_gGrid_init(GGrid=dom_a, CoordChars=trim(shr_flds_dom_coord), & - OtherChars=trim(shr_flds_dom_other), lsize=lsize) - ! - ! Allocate memory - ! - allocate(data(lsize)) - ! - ! Initialize attribute vector with special value - ! - call mct_gsMap_orderedPoints(gsMap_a, iam, idata) - call mct_gGrid_importIAttr(dom_a, 'GlobGridNum', idata, lsize) - ! - ! Determine domain - ! Initialize attribute vector with special value - ! - data(:) = -9999.0_R8 - call mct_gGrid_importRAttr(dom_a, "lat", data, lsize) - call mct_gGrid_importRAttr(dom_a, "lon", data, lsize) - call mct_gGrid_importRAttr(dom_a, "area", data, lsize) - call mct_gGrid_importRAttr(dom_a, "aream", data, lsize) - data(:) = 0.0_R8 - call mct_gGrid_importRAttr(dom_a, "mask", data, lsize) - data(:) = 1.0_R8 - call mct_gGrid_importRAttr(dom_a, "frac", data, lsize) - ! - ! Fill in correct values for domain components - ! - do index = 1, columns_on_task - data(index) = get_dlat_p(index) - end do - call mct_gGrid_importRAttr(dom_a, "lat", data, lsize) - - do index = 1, columns_on_task - data(index) = get_dlon_p(index) - end do - call mct_gGrid_importRAttr(dom_a, "lon", data, lsize) - - do index = 1, columns_on_task - data(index) = get_area_p(index) - end do - call mct_gGrid_importRAttr(dom_a, "area", data, lsize) - - data(1:columns_on_task) = 1._r8 ! mask - call mct_gGrid_importRAttr(dom_a, "mask", data, lsize) - deallocate(data) - - end subroutine atm_domain_mct - - !=========================================================================== - - subroutine atm_read_srfrest_mct(EClock, x2a_a, a2x_a) - use physics_grid, only: columns_on_task, ngcols => num_global_phys_cols - - !----------------------------------------------------------------------- - use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile - use cam_pio_utils, only: cam_pio_newdecomp - ! - ! Arguments - ! - type(ESMF_Clock), intent(inout) :: EClock - type(mct_aVect), intent(inout) :: x2a_a - type(mct_aVect), intent(inout) :: a2x_a - ! - ! Local variables - ! - character(len=cl) :: fname_srf_cam ! surface restart filename - character(len=cl) :: pname_srf_cam ! surface restart full pathname - integer :: rcode ! return error code - integer :: yr_spec ! Current year - integer :: mon_spec ! Current month - integer :: day_spec ! Current day - integer :: sec_spec ! Current time of day (sec) - integer :: nf_x2a, nf_a2x, k - integer :: err_handling - real(r8), allocatable :: tmp(:) - type(file_desc_t) :: file - type(io_desc_t), pointer :: iodesc - type(var_desc_t) :: varid - character(CL) :: itemc ! string converted to char - type(mct_string) :: mstring ! mct char type - !----------------------------------------------------------------------- - - nullify(iodesc) - ! Determine and open surface restart dataset - - call seq_timemgr_EClockGetData(EClock, curr_yr=yr_spec, & - curr_mon=mon_spec, curr_day=day_spec, curr_tod=sec_spec) - - ! Determine and open surface restart dataset - - if (dart_mode) then - fname_srf_cam = interpret_filename_spec(rsfilename_spec_cam, & - yr_spec=yr_spec, mon_spec=mon_spec, day_spec=day_spec, & - sec_spec=sec_spec) - pname_srf_cam = fname_srf_cam - else - fname_srf_cam = interpret_filename_spec(rsfilename_spec_cam, & - case=cam_initfiles_get_caseid(), yr_spec=yr_spec, & - mon_spec=mon_spec, day_spec=day_spec, sec_spec= sec_spec) - pname_srf_cam = trim(cam_initfiles_get_restdir())//fname_srf_cam - end if - call cam_get_file(pname_srf_cam, fname_srf_cam) - - call cam_pio_openfile(File, fname_srf_cam, 0) - allocate(iodesc) - call cam_pio_newdecomp(iodesc, (/ ngcols /), int(dof, PIO_OFFSET_KIND), & - pio_double) - allocate(tmp(size(dof))) - - nf_x2a = mct_aVect_nRattr(x2a_a) - do k = 1, nf_x2a - call mct_aVect_getRList(mstring, k, x2a_a) - itemc = mct_string_toChar(mstring) - call mct_string_clean(mstring) - - call pio_seterrorhandling(File, pio_bcast_error, & - oldmethod=err_handling) - rcode = pio_inq_varid(File, 'x2a_'//trim(itemc), varid) - if (rcode == pio_noerr) then - call pio_read_darray(File, varid, iodesc, tmp, rcode) - x2a_a%rattr(k, :) = tmp(:) - else - if (masterproc) then - write(iulog, *) 'srfrest warning: field ', trim(itemc), & - ' is not on restart file' - write(iulog, *) 'Setting to 0 for backwards compatibility' - end if - x2a_a%rattr(k,:) = 0._r8 - end if - call pio_seterrorhandling(File, err_handling) - end do - - nf_a2x = mct_aVect_nRattr(a2x_a) - do k = 1, nf_a2x - call mct_aVect_getRList(mstring,k,a2x_a) - itemc = mct_string_toChar(mstring) - call mct_string_clean(mstring) - - rcode = pio_inq_varid(File,'a2x_'//trim(itemc), varid) - call pio_read_darray(File, varid, iodesc, tmp, rcode) - a2x_a%rattr(k,:) = tmp(:) - end do - - call pio_freedecomp(File, iodesc) - deallocate(iodesc) - call cam_pio_closefile(File) - deallocate(tmp) - - end subroutine atm_read_srfrest_mct - - !=========================================================================== - - subroutine atm_write_srfrest_mct(x2a_a, a2x_a, & - yr_spec, mon_spec, day_spec, sec_spec) - - !----------------------------------------------------------------------- - use physics_grid, only: ngcols => num_global_phys_cols - use cam_pio_utils, only: cam_pio_createfile, cam_pio_closefile - use cam_pio_utils, only: cam_pio_newdecomp -!!XXgoldyXX: v import history -! use cam_history_support, only: fillvalue -real(r8) :: fillvalue = 9.87e36_r8 -!!XXgoldyXX: ^ import history - ! - ! Arguments - ! - type(mct_aVect), intent(in) :: x2a_a - type(mct_aVect), intent(in) :: a2x_a - integer, intent(in) :: yr_spec ! Simulation year - integer, intent(in) :: mon_spec ! Simulation month - integer, intent(in) :: day_spec ! Simulation day - integer, intent(in) :: sec_spec ! Seconds into current sim day - ! - ! Local variables - ! - character(len=cl) :: fname_srf_cam ! surface restart filename - integer :: rcode ! return error code - integer :: nf_x2a, nf_a2x, dimid(1), k - type(file_desc_t) :: file - type(var_desc_t), pointer :: varid_x2a(:), varid_a2x(:) - type(io_desc_t), pointer :: iodesc - character(CL) :: itemc ! string converted to char - type(mct_string) :: mstring ! mct char type - !----------------------------------------------------------------------- - - nullify(iodesc) - fname_srf_cam = interpret_filename_spec(rsfilename_spec_cam, & - yr_spec=yr_spec, mon_spec=mon_spec, day_spec=day_spec, & - sec_spec= sec_spec) - - call cam_pio_createfile(File, fname_srf_cam, 0) - allocate(iodesc) - call cam_pio_newdecomp(iodesc, (/ ngcols /), int(dof, PIO_OFFSET_KIND), & - pio_double) - - nf_x2a = mct_aVect_nRattr(x2a_a) - allocate(varid_x2a(nf_x2a)) - - rcode = pio_def_dim(File, 'x2a_nx', ngcols, dimid(1)) - do k = 1, nf_x2a - call mct_aVect_getRList(mstring,k,x2a_a) - itemc = mct_string_toChar(mstring) - call mct_string_clean(mstring) - rcode = pio_def_var(File, 'x2a_'//trim(itemc), PIO_DOUBLE, dimid, & - varid_x2a(k)) - rcode = pio_put_att(File, varid_x2a(k), "_fillvalue", fillvalue) - end do - - nf_a2x = mct_aVect_nRattr(a2x_a) - allocate(varid_a2x(nf_a2x)) - - rcode = pio_def_dim(File, 'a2x_nx', ngcols, dimid(1)) - do k = 1, nf_a2x - call mct_aVect_getRList(mstring,k, a2x_a) - itemc = mct_string_toChar(mstring) - call mct_string_clean(mstring) - rcode = PIO_def_var(File, 'a2x_'//trim(itemc), PIO_DOUBLE, dimid, & - varid_a2x(k)) - rcode = PIO_put_att(File, varid_a2x(k), "_fillvalue", fillvalue) - end do - - rcode = pio_enddef(File) ! error return code, might be enddef already - - do k = 1, nf_x2a - call pio_write_darray(File, varid_x2a(k), iodesc, x2a_a%rattr(k,:), & - rcode) - end do - - do k = 1, nf_a2x - call pio_write_darray(File, varid_a2x(k), iodesc, a2x_a%rattr(k,:), & - rcode) - end do - - deallocate(varid_x2a, varid_a2x) - - call pio_freedecomp(File, iodesc) - deallocate(iodesc) - call cam_pio_closefile(file) - - end subroutine atm_write_srfrest_mct - -end module atm_comp_mct diff --git a/src/cpl/mct/atm_import_export.F90 b/src/cpl/mct/atm_import_export.F90 deleted file mode 100644 index c58d3aba..00000000 --- a/src/cpl/mct/atm_import_export.F90 +++ /dev/null @@ -1,397 +0,0 @@ -module atm_import_export - - use shr_kind_mod, only: r8 => shr_kind_r8, cl => shr_kind_cl - use time_manager, only: get_nstep - use cam_logfile, only: iulog - use spmd_utils, only: masterproc - - implicit none - private - save - - ! Public interfaces - public :: atm_import - public :: atm_export - - ! Private module data - integer, parameter :: debug = 0 ! internal debug level - character(len=*), parameter :: modname = '(cam_import_export) ' - character(len=*), parameter :: F01 = "("//modname//",a, i8,2x,i8,2x,d21.14)" - -!============================================================================ -CONTAINS -!============================================================================ - - subroutine atm_import(x2a, cam_in, restart_init) - - !----------------------------------------------------------------------- - use cam_cpl_indices ! Temporary exception to naked use - use camsrfexch, only: cam_in_t - use shr_const_mod, only: shr_const_stebol - use shr_sys_mod, only: shr_sys_abort - use time_manager, only: is_first_step - use physics_grid, only: columns_on_task -!!XXgoldyXX: v figure out what to do with constituents -! use seq_drydep_mod, only: n_drydep -! use shr_fire_emis_mod, only: shr_fire_emis_mechcomps_n -! use co2_cycle, only: c_i, co2_readFlux_ocn, co2_readFlux_fuel -! use co2_cycle, only: co2_transport, co2_time_interp_ocn -! use co2_cycle, only: co2_time_interp_fuel -! use co2_cycle, only: data_flux_ocn, data_flux_fuel -! use physconst, only: mwco2 -!!XXgoldyXX: ^ figure out what to do with constituents - ! - ! Arguments - ! - real(r8), intent(in) :: x2a(:,:) - type(cam_in_t), intent(inout) :: cam_in - logical, optional, intent(in) :: restart_init - ! - ! Local variables - ! - integer :: index - logical, save :: first_time = .true. - integer, parameter :: ndst = 2 - integer, target :: spc_ndx(ndst) - integer, pointer :: dst_a5_ndx, dst_a7_ndx - integer, pointer :: dst_a1_ndx, dst_a3_ndx - integer :: nstep - logical :: overwrite_flds - !----------------------------------------------------------------------- - - overwrite_flds = .true. - ! don't overwrite fields if invoked during the initialization phase - ! of a 'continue' or 'branch' run type with data from .rs file - if (present(restart_init)) then - overwrite_flds = .not. restart_init - end if - -!!XXgoldyXX: v figure out what to do with constituents -#if 0 - ! CESM sign convention is that fluxes are positive downward - do index = 1, columns_on_task - if (overwrite_flds) then - cam_in%wsx(index) = -x2a(index_x2a_Faxx_taux, index) - cam_in%wsy(index) = -x2a(index_x2a_Faxx_tauy, index) - cam_in%shf(index) = -x2a(index_x2a_Faxx_sen, index) - cam_in%cflx(index,1) = -x2a(index_x2a_Faxx_evap, index) - end if - cam_in%lhf(index) = -x2a(index_x2a_Faxx_lat, index) - cam_in%lwup(index) = -x2a(index_x2a_Faxx_lwup, index) - cam_in%asdir(index) = x2a(index_x2a_Sx_avsdr, index) - cam_in%aldir(index) = x2a(index_x2a_Sx_anidr, index) - cam_in%asdif(index) = x2a(index_x2a_Sx_avsdf, index) - cam_in%aldif(index) = x2a(index_x2a_Sx_anidf, index) - cam_in%ts(index) = x2a(index_x2a_Sx_t, index) - cam_in%sst(index) = x2a(index_x2a_So_t, index) - cam_in%snowhland(index) = x2a(index_x2a_Sl_snowh, index) - cam_in%snowhice(index) = x2a(index_x2a_Si_snowh, index) - cam_in%tref(index) = x2a(index_x2a_Sx_tref, index) - cam_in%qref(index) = x2a(index_x2a_Sx_qref, index) - cam_in%u10(index) = x2a(index_x2a_Sx_u10, index) - cam_in%icefrac(index) = x2a(index_x2a_Sf_ifrac, index) - cam_in%ocnfrac(index) = x2a(index_x2a_Sf_ofrac, index) - cam_in%landfrac(index) = x2a(index_x2a_Sf_lfrac, index) - - if ( associated(cam_in%ram1) ) & - cam_in%ram1(index) = x2a(index_x2a_Sl_ram1, index) - if ( associated(cam_in%fv) ) & - cam_in%fv(index) = x2a(index_x2a_Sl_fv, index) - if ( associated(cam_in%soilw) ) & - cam_in%soilw(index) = x2a(index_x2a_Sl_soilw, index) - if ( associated(cam_in%dstflx) ) then - cam_in%dstflx(index,1) = x2a(index_x2a_Fall_flxdst1, index) - cam_in%dstflx(index,2) = x2a(index_x2a_Fall_flxdst2, index) - cam_in%dstflx(index,3) = x2a(index_x2a_Fall_flxdst3, index) - cam_in%dstflx(index,4) = x2a(index_x2a_Fall_flxdst4, index) - endif - if ( associated(cam_in%meganflx) ) then - cam_in%meganflx(i,1:shr_megan_mechcomps_n) = & - x2a(index_x2a_Fall_flxvoc:index_x2a_Fall_flxvoc+shr_megan_mechcomps_n-1, index) - endif - - ! Fire emission fluxes - if ( associated(cam_in%fireflx) .and. associated(cam_in%fireztop) ) then - cam_in%fireflx(i,:shr_fire_emis_mechcomps_n) = & - x2a(index_x2a_Fall_flxfire:index_x2a_Fall_flxfire+shr_fire_emis_mechcomps_n-1, index) - cam_in%fireztop(index) = x2a(index_x2a_Sl_ztopfire, index) - endif - - ! dry dep velocities - if ( index_x2a_Sl_ddvel/= 0 .and. n_drydep>0 ) then - cam_in%depvel(index,:n_drydep) = & - x2a(index_x2a_Sl_ddvel:index_x2a_Sl_ddvel+n_drydep-1, index) - endif - ! - ! fields needed to calculate water isotopes to ocean evaporation processes - ! - cam_in%ustar(index) = x2a(index_x2a_So_ustar,index) - cam_in%re(index) = x2a(index_x2a_So_re,index) - cam_in%ssq(index) = x2a(index_x2a_So_ssq,index) - ! - ! bgc scenarios - ! - if (index_x2a_Fall_fco2_lnd /= 0) then - cam_in%fco2_lnd(index) = -x2a(index_x2a_Fall_fco2_lnd,index) - end if - if (index_x2a_Faoo_fco2_ocn /= 0) then - cam_in%fco2_ocn(index) = -x2a(index_x2a_Faoo_fco2_ocn,index) - end if - if (index_x2a_Faoo_fdms_ocn /= 0) then - cam_in%fdms(index) = -x2a(index_x2a_Faoo_fdms_ocn,index) - end if - end do - - ! Get total co2 flux from components, - ! Note - co2_transport determines if cam_in%cflx(i,c_i(1:4)) is - ! allocated - if (co2_transport().and.overwrite_flds) then - - ! Interpolate in time for flux data read in - if (co2_readFlux_ocn) then - call co2_time_interp_ocn - end if - if (co2_readFlux_fuel) then - call co2_time_interp_fuel - end if - - ! from ocn : data read in or from coupler or zero - ! from fuel: data read in or zero - ! from lnd : through coupler or zero - do c = begchunk,endchunk - ncols = get_ncols_p(c) - do i = 1,ncols - - ! all co2 fluxes in unit kgCO2/m2/s ! co2 flux from ocn - if (index_x2a_Faoo_fco2_ocn /= 0) then - cam_in%cflx(i,c_i(1)) = cam_in%fco2_ocn(index) - else if (co2_readFlux_ocn) then - ! convert from molesCO2/m2/s to kgCO2/m2/s - cam_in%cflx(i,c_i(1)) = & - -data_flux_ocn%co2flx(i,c)*(1._r8- cam_in%landfrac(index)) & - *mwco2*1.0e-3_r8 - else - cam_in%cflx(i,c_i(1)) = 0._r8 - end if - - ! co2 flux from fossil fuel - if (co2_readFlux_fuel) then - cam_in%cflx(i,c_i(2)) = data_flux_fuel%co2flx(i,c) - else - cam_in%cflx(i,c_i(2)) = 0._r8 - end if - - ! co2 flux from land (cpl already multiplies flux by land fraction) - if (index_x2a_Fall_fco2_lnd /= 0) then - cam_in%cflx(i,c_i(3)) = cam_in%fco2_lnd(index) - else - cam_in%cflx(i,c_i(3)) = 0._r8 - end if - - ! merged co2 flux - cam_in%cflx(i,c_i(4)) = cam_in%cflx(i,c_i(1)) + & - cam_in%cflx(i,c_i(2)) + & - cam_in%cflx(i,c_i(3)) - end do - end do - end if - ! - ! if first step, determine longwave up flux from the surface temperature - ! - if (first_time) then - if (is_first_step()) then - do c = begchunk, endchunk - ncols = get_ncols_p(c) - do i = 1,ncols - cam_in%lwup(index) = shr_const_stebol*(cam_in%ts(index)**4) - end do - end do - end if - first_time = .false. - end if - - !----------------------------------------------------------------- - ! Debug output - !----------------------------------------------------------------- - - if (debug > 0 .and. masterproc) then - nstep = get_nstep() - ig = 1 - do c = begchunk, endchunk - ncols = get_ncols_p(c) - do i = 1,ncols - write(iulog,F01)'import: nstep, ig, Faxx_tauy = ',nstep,ig,x2a(index_x2a_Faxx_tauy,ig) - write(iulog,F01)'import: nstep, ig, Faxx_taux = ',nstep,ig,x2a(index_x2a_Faxx_taux,ig) - write(iulog,F01)'import: nstep, ig, Faxx_shf = ',nstep,ig,x2a(index_x2a_Faxx_sen,ig) - write(iulog,F01)'import: nstep, ig, Faxx_lhf = ',nstep,ig,x2a(index_x2a_Faxx_lat,ig) - write(iulog,F01)'import: nstep, ig, Sx_asdir = ',nstep,ig,x2a(index_x2a_Sx_avsdr,ig) - write(iulog,F01)'import: nstep, ig, Sx_aldir = ',nstep,ig,x2a(index_x2a_Sx_anidr,ig) - write(iulog,F01)'import: nstep, ig, Sx_asdif = ',nstep,ig,x2a(index_x2a_Sx_avsdf,ig) - write(iulog,F01)'import: nstep, ig, Sx_aldif = ',nstep,ig,x2a(index_x2a_Sx_anidf,ig) - write(iulog,F01)'import: nstep, ig, Sx_t = ',nstep,ig,x2a(index_x2a_Sx_t,ig) - write(iulog,F01)'import: nstep, ig, Sl_snowh = ',nstep,ig,x2a(index_x2a_Sl_snowh,ig) - write(iulog,F01)'import: nstep, ig, Si_snowh = ',nstep,ig,x2a(index_x2a_Si_snowh,ig) - write(iulog,F01)'import: nstep, ig, Sf_ifrac = ',nstep,ig,x2a(index_x2a_Sf_ifrac,ig) - write(iulog,F01)'import: nstep, ig, Sf_ofrac = ',nstep,ig,x2a(index_x2a_Sf_ofrac,ig) - write(iulog,F01)'import: nstep, ig, Sf_lfrac = ',nstep,ig,x2a(index_x2a_Sf_lfrac,ig) - if (.not. first_time .and. .not. is_first_step()) then - write(iulog,F01)'import: nstep, ig, Faxa_lwup = ',nstep,ig,x2a(index_x2a_Faxx_lwup, ig) - else - write(iulog,F01)'import: nstep, ig, Faxa_lwup = ',nstep,ig,cam_in%lwup(index) - end if - ig = ig + 1 - end do - end do - end if -#endif -!!XXgoldyXX: ^ figure out what to do with constituents - - end subroutine atm_import - - !============================================================================ - - subroutine atm_export(cam_out, a2x) - - !------------------------------------------------------------------- - use camsrfexch, only: cam_out_t - use physics_grid, only: columns_on_task - use cam_cpl_indices ! Temporary exception to naked use - ! - ! Arguments - ! - type(cam_out_t), intent(in) :: cam_out - real(r8), intent(inout) :: a2x(:,:) - ! - ! Local variables - ! - integer :: avsize, avnat - integer :: index - integer :: nstep - !----------------------------------------------------------------------- - - ! Copy from component arrays into chunk array data structure - ! Rearrange data from chunk structure into lat-lon buffer and subsequently - ! create attribute vector - -!!XXgoldyXX: v figure out what to do with constituents -#if 0 - do index = 1, columns_on_task - a2x(index_a2x_Sa_pslv,ig) = cam_out%psl(i) - a2x(index_a2x_Sa_z,ig) = cam_out%zbot(i) - a2x(index_a2x_Sa_topo,ig) = cam_out%topo(i) - a2x(index_a2x_Sa_u,ig) = cam_out%ubot(i) - a2x(index_a2x_Sa_v,ig) = cam_out%vbot(i) - a2x(index_a2x_Sa_tbot,ig) = cam_out%tbot(i) - a2x(index_a2x_Sa_ptem,ig) = cam_out%thbot(i) - a2x(index_a2x_Sa_pbot,ig) = cam_out%pbot(i) - a2x(index_a2x_Sa_shum,ig) = cam_out%qbot(i,1) - a2x(index_a2x_Sa_dens,ig) = cam_out%rho(i) - a2x(index_a2x_Faxa_swnet,ig) = cam_out%netsw(i) - a2x(index_a2x_Faxa_lwdn,ig) = cam_out%flwds(i) - a2x(index_a2x_Faxa_rainc,ig) = (cam_out%precc(i)-cam_out%precsc(i))*1000._r8 - a2x(index_a2x_Faxa_rainl,ig) = (cam_out%precl(i)-cam_out%precsl(i))*1000._r8 - a2x(index_a2x_Faxa_snowc,ig) = cam_out%precsc(i)*1000._r8 - a2x(index_a2x_Faxa_snowl,ig) = cam_out%precsl(i)*1000._r8 - a2x(index_a2x_Faxa_swndr,ig) = cam_out%soll(i) - a2x(index_a2x_Faxa_swvdr,ig) = cam_out%sols(i) - a2x(index_a2x_Faxa_swndf,ig) = cam_out%solld(i) - a2x(index_a2x_Faxa_swvdf,ig) = cam_out%solsd(i) - - ! aerosol deposition fluxes - a2x(index_a2x_Faxa_bcphidry,ig) = cam_out%bcphidry(i) - a2x(index_a2x_Faxa_bcphodry,ig) = cam_out%bcphodry(i) - a2x(index_a2x_Faxa_bcphiwet,ig) = cam_out%bcphiwet(i) - a2x(index_a2x_Faxa_ocphidry,ig) = cam_out%ocphidry(i) - a2x(index_a2x_Faxa_ocphodry,ig) = cam_out%ocphodry(i) - a2x(index_a2x_Faxa_ocphiwet,ig) = cam_out%ocphiwet(i) - a2x(index_a2x_Faxa_dstwet1,ig) = cam_out%dstwet1(i) - a2x(index_a2x_Faxa_dstdry1,ig) = cam_out%dstdry1(i) - a2x(index_a2x_Faxa_dstwet2,ig) = cam_out%dstwet2(i) - a2x(index_a2x_Faxa_dstdry2,ig) = cam_out%dstdry2(i) - a2x(index_a2x_Faxa_dstwet3,ig) = cam_out%dstwet3(i) - a2x(index_a2x_Faxa_dstdry3,ig) = cam_out%dstdry3(i) - a2x(index_a2x_Faxa_dstwet4,ig) = cam_out%dstwet4(i) - a2x(index_a2x_Faxa_dstdry4,ig) = cam_out%dstdry4(i) - - if (index_a2x_Sa_co2prog /= 0) then - a2x(index_a2x_Sa_co2prog,ig) = cam_out%co2prog(i) ! atm prognostic co2 - end if - if (index_a2x_Sa_co2diag /= 0) then - a2x(index_a2x_Sa_co2diag,ig) = cam_out%co2diag(i) ! atm diagnostic co2 - end if - if (index_a2x_Faxa_nhx > 0 ) then - a2x(index_a2x_Faxa_nhx,ig) = cam_out%nhx_nitrogen_flx(i) - endif - if (index_a2x_Faxa_noy > 0 ) then - a2x(index_a2x_Faxa_noy,ig) = cam_out%noy_nitrogen_flx(i) - endif - - ig = ig + 1 - end do - end do - - !----------------------------------------------------------------- - ! Debug output - !----------------------------------------------------------------- - - if (debug > 0 .and. masterproc) then - nstep = get_nstep() - ig = 1 - do c = begchunk, endchunk - ncols = get_ncols_p(c) - do i = 1,ncols - write(iulog,F01)'export: nstep, ig, Sa_z = ',nstep,ig,a2x(index_a2x_Sa_z,ig) - write(iulog,F01)'export: nstep, ig, Sa_topo = ',nstep,ig,a2x(index_a2x_Sa_topo,ig) - write(iulog,F01)'export: nstep, ig, Sa_u = ',nstep,ig,a2x(index_a2x_Sa_u,ig) - write(iulog,F01)'export: nstep, ig, Sa_v = ',nstep,ig,a2x(index_a2x_Sa_v,ig) - write(iulog,F01)'export: nstep, ig, Sa_tbot = ',nstep,ig,a2x(index_a2x_Sa_tbot,ig) - write(iulog,F01)'export: nstep, ig, Sa_ptem = ',nstep,ig,a2x(index_a2x_Sa_ptem,ig) - write(iulog,F01)'export: nstep, ig, Sa_pbot = ',nstep,ig,a2x(index_a2x_Sa_pbot,ig) - write(iulog,F01)'export: nstep, ig, Sa_shum = ',nstep,ig,a2x(index_a2x_Sa_shum,ig) - write(iulog,F01)'export: nstep, ig, Sa_dens = ',nstep,ig,a2x(index_a2x_Sa_dens,ig) - write(iulog,F01)'export: nstep, ig, Faxa_swnet = ',nstep,ig,a2x(index_a2x_Faxa_swnet,ig) - write(iulog,F01)'export: nstep, ig, Faxa_lwdn = ',nstep,ig,a2x(index_a2x_Faxa_lwdn,ig) - write(iulog,F01)'export: nstep, ig, Faxa_rainc = ',nstep,ig,a2x(index_a2x_Faxa_rainc,ig) - write(iulog,F01)'export: nstep, ig, Faxa_rainl = ',nstep,ig,a2x(index_a2x_Faxa_rainl,ig) - write(iulog,F01)'export: nstep, ig, Faxa_snowc = ',nstep,ig,a2x(index_a2x_Faxa_snowc,ig) - write(iulog,F01)'export: nstep, ig, Faxa_snowl = ',nstep,ig,a2x(index_a2x_Faxa_snowl,ig) - write(iulog,F01)'export: nstep, ig, Faxa_swndr = ',nstep,ig,a2x(index_a2x_Faxa_swndr,ig) - write(iulog,F01)'export: nstep, ig, Faxa_swvdr = ',nstep,ig,a2x(index_a2x_Faxa_swvdr,ig) - write(iulog,F01)'export: nstep, ig, Faxa_swndf = ',nstep,ig,a2x(index_a2x_Faxa_swndf,ig) - write(iulog,F01)'export: nstep, ig, Faxa_swvdf = ',nstep,ig,a2x(index_a2x_Faxa_swvdf,ig) - write(iulog,F01)'export: nstep, ig, Faxa_bcphidry = ',nstep,ig,a2x(index_a2x_Faxa_bcphidry,ig) - write(iulog,F01)'export: nstep, ig, Faxa_bcphodry = ',nstep,ig,a2x(index_a2x_Faxa_bcphodry,ig) - write(iulog,F01)'export: nstep, ig, Faxa_bcphiwet = ',nstep,ig,a2x(index_a2x_Faxa_bcphiwet,ig) - write(iulog,F01)'export: nstep, ig, Faxa_ocphidry = ',nstep,ig,a2x(index_a2x_Faxa_ocphidry,ig) - write(iulog,F01)'export: nstep, ig, Faxa_ocphodry = ',nstep,ig,a2x(index_a2x_Faxa_ocphodry,ig) - write(iulog,F01)'export: nstep, ig, Faxa_ocphidry = ',nstep,ig,a2x(index_a2x_Faxa_ocphiwet,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstwet1,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstdry1,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstwet2,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstdry2,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstwet3,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstdry3,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstwet4,ig) - write(iulog,F01)'export: nstep, ig, Faxa_dstwet1 = ',nstep,ig,a2x(index_a2x_Faxa_dstdry4,ig) - if (index_a2x_Sa_co2prog /= 0) then - write(iulog,F01)'export: nstep, ig, Sa_co2prog = ',nstep,ig,a2x(index_a2x_Sa_co2prog,ig) - end if - if (index_a2x_Sa_co2diag /= 0) then - write(iulog,F01)'export: nstep, ig, Sa_co2diag = ',nstep,ig,a2x(index_a2x_Sa_co2diag,ig) - end if - if (index_a2x_Faxa_nhx > 0 ) then - write(iulog,F01)'export: nstep, ig, Faxa_nhx = ',nstep,ig,a2x(index_a2x_Faxa_nhx,ig) - endif - if (index_a2x_Faxa_noy > 0 ) then - write(iulog,F01)'export: nstep, ig, Faxa_noy = ',nstep,ig,a2x(index_a2x_Faxa_noy,ig) - endif - ig = ig + 1 - end do - end do - end if -#endif -!!XXgoldyXX: ^ figure out what to do with constituents - - end subroutine atm_export - -end module atm_import_export diff --git a/src/cpl/mct/cam_cpl_indices.F90 b/src/cpl/mct/cam_cpl_indices.F90 deleted file mode 100644 index 5237e564..00000000 --- a/src/cpl/mct/cam_cpl_indices.F90 +++ /dev/null @@ -1,234 +0,0 @@ -module cam_cpl_indices - - use seq_flds_mod, only: seq_flds_x2a_fields, seq_flds_a2x_fields - use mct_mod, only: mct_aVect, mct_aVect_init, mct_avect_indexra - use mct_mod, only: mct_aVect_clean - use seq_drydep_mod, only: drydep_fields_token, lnd_drydep - use shr_megan_mod, only: shr_megan_fields_token, shr_megan_mechcomps_n - use shr_fire_emis_mod, only: shr_fire_emis_fields_token - use shr_fire_emis_mod, only: shr_fire_emis_ztop_token - use shr_fire_emis_mod, only: shr_fire_emis_mechcomps_n - use srf_field_check, only: set_active_Sl_ram1, set_active_Sl_fv - use srf_field_check, only: set_active_Sl_soilw, set_active_Fall_flxdst1 - use srf_field_check, only: set_active_Fall_flxvoc, set_active_Fall_flxfire - use srf_field_check, only: set_active_Fall_fco2_lnd - use srf_field_check, only: set_active_Faoo_fco2_ocn, set_active_Faxa_nhx - use srf_field_check, only: set_active_Faxa_noy - - implicit none - - SAVE - public - - integer :: index_a2x_Sa_z ! bottom atm level height - integer :: index_a2x_Sa_topo ! surface topographic height - integer :: index_a2x_Sa_u ! bottom atm level zon wind - integer :: index_a2x_Sa_v ! bottom atm level mer wind - integer :: index_a2x_Sa_tbot ! bottom atm level temp - integer :: index_a2x_Sa_ptem ! bottom atm level pot temp - integer :: index_a2x_Sa_shum ! bottom atm level spec hum - integer :: index_a2x_Sa_dens ! bottom atm level air den - integer :: index_a2x_Sa_pbot ! bottom atm level pressure - integer :: index_a2x_Sa_pslv ! sea level atm pressure - integer :: index_a2x_Faxa_lwdn ! downward lw heat flux - integer :: index_a2x_Faxa_rainc ! prec: liquid "convective" - integer :: index_a2x_Faxa_rainl ! prec: liquid "large scale" - integer :: index_a2x_Faxa_snowc ! prec: frozen "convective" - integer :: index_a2x_Faxa_snowl ! prec: frozen "large scale" - integer :: index_a2x_Faxa_swndr ! sw: nir direct downward - integer :: index_a2x_Faxa_swvdr ! sw: vis direct downward - integer :: index_a2x_Faxa_swndf ! sw: nir diffuse downward - integer :: index_a2x_Faxa_swvdf ! sw: vis diffuse downward - integer :: index_a2x_Faxa_swnet ! sw: net - integer :: index_a2x_Faxa_bcphidry ! flux: Black Carbon hydrophilic dry deposition - integer :: index_a2x_Faxa_bcphodry ! flux: Black Carbon hydrophobic dry deposition - integer :: index_a2x_Faxa_bcphiwet ! flux: Black Carbon hydrophilic wet deposition - integer :: index_a2x_Faxa_ocphidry ! flux: Organic Carbon hydrophilic dry deposition - integer :: index_a2x_Faxa_ocphodry ! flux: Organic Carbon hydrophobic dry deposition - integer :: index_a2x_Faxa_ocphiwet ! flux: Organic Carbon hydrophilic dry deposition - integer :: index_a2x_Faxa_dstwet1 ! flux: Size 1 dust -- wet deposition - integer :: index_a2x_Faxa_dstwet2 ! flux: Size 2 dust -- wet deposition - integer :: index_a2x_Faxa_dstwet3 ! flux: Size 3 dust -- wet deposition - integer :: index_a2x_Faxa_dstwet4 ! flux: Size 4 dust -- wet deposition - integer :: index_a2x_Faxa_dstdry1 ! flux: Size 1 dust -- dry deposition - integer :: index_a2x_Faxa_dstdry2 ! flux: Size 2 dust -- dry deposition - integer :: index_a2x_Faxa_dstdry3 ! flux: Size 3 dust -- dry deposition - integer :: index_a2x_Faxa_dstdry4 ! flux: Size 4 dust -- dry deposition - integer :: index_a2x_Sa_co2prog ! bottom atm level prognostic co2 - integer :: index_a2x_Sa_co2diag ! bottom atm level diagnostic co2 - integer :: index_a2x_Faxa_nhx ! flux: Nitrogen deposition - integer :: index_a2x_Faxa_noy ! flux: Nitrogen deposition - - integer :: index_x2a_Sx_t ! surface temperature - integer :: index_x2a_So_t ! sea surface temperature - integer :: index_x2a_Sf_lfrac ! surface land fraction - integer :: index_x2a_Sf_ifrac ! surface ice fraction - integer :: index_x2a_Sf_ofrac ! surface ocn fraction - integer :: index_x2a_Sx_tref ! 2m reference temperature - integer :: index_x2a_Sx_qref ! 2m reference specific humidity - integer :: index_x2a_Sx_avsdr ! albedo, visible, direct - integer :: index_x2a_Sx_anidr ! albedo, near-ir, direct - integer :: index_x2a_Sx_avsdf ! albedo, visible, diffuse - integer :: index_x2a_Sx_anidf ! albedo, near-ir, diffuse - integer :: index_x2a_Sl_snowh ! surface snow depth over land - integer :: index_x2a_Si_snowh ! surface snow depth over ice - integer :: index_x2a_Sl_fv ! friction velocity - integer :: index_x2a_Sl_ram1 ! aerodynamical resistance - integer :: index_x2a_Sl_soilw ! volumetric soil water - integer :: index_x2a_Faxx_taux ! wind stress, zonal - integer :: index_x2a_Faxx_tauy ! wind stress, meridional - integer :: index_x2a_Faxx_lat ! latent heat flux - integer :: index_x2a_Faxx_sen ! sensible heat flux - integer :: index_x2a_Faxx_lwup ! upward longwave heat flux - integer :: index_x2a_Faxx_evap ! evaporation water flux - integer :: index_x2a_Fall_flxdst1 ! dust flux size bin 1 - integer :: index_x2a_Fall_flxdst2 ! dust flux size bin 2 - integer :: index_x2a_Fall_flxdst3 ! dust flux size bin 3 - integer :: index_x2a_Fall_flxdst4 ! dust flux size bin 4 - integer :: index_x2a_Fall_flxvoc ! MEGAN emissions fluxes - integer :: index_x2a_Fall_flxfire ! Fire emissions fluxes - integer :: index_x2a_Sl_ztopfire ! Fire emissions fluxes top of vert distribution - integer :: index_x2a_Fall_fco2_lnd ! co2 flux from land - integer :: index_x2a_Faoo_fco2_ocn ! co2 flux from ocean - integer :: index_x2a_Faoo_fdms_ocn ! dms flux from ocean - integer :: index_x2a_So_ustar ! surface friction velocity in ocean - integer :: index_x2a_So_re ! square of atm/ocn exch. coeff - integer :: index_x2a_So_ssq ! surface saturation specific humidity in ocean - integer :: index_x2a_Sl_ddvel ! dry deposition velocities from land - integer :: index_x2a_Sx_u10 ! 10m wind - -contains - - subroutine cam_cpl_indices_set( ) - - type(mct_aVect) :: a2x ! temporary - type(mct_aVect) :: x2a ! temporary - - ! Determine attribute vector indices - - ! create temporary attribute vectors - call mct_aVect_init(x2a, rList=seq_flds_x2a_fields, lsize=1) - call mct_aVect_init(a2x, rList=seq_flds_a2x_fields, lsize=1) - - ! Initialize av indices - index_x2a_Sx_avsdr = mct_avect_indexra(x2a,'Sx_avsdr') - index_x2a_Sx_anidr = mct_avect_indexra(x2a,'Sx_anidr') - index_x2a_Sx_avsdf = mct_avect_indexra(x2a,'Sx_avsdf') - index_x2a_Sx_anidf = mct_avect_indexra(x2a,'Sx_anidf') - index_x2a_Sx_t = mct_avect_indexra(x2a,'Sx_t') - index_x2a_So_t = mct_avect_indexra(x2a,'So_t') - index_x2a_Sl_snowh = mct_avect_indexra(x2a,'Sl_snowh') - index_x2a_Si_snowh = mct_avect_indexra(x2a,'Si_snowh') - - index_x2a_Sl_fv = mct_avect_indexra(x2a,'Sl_fv') - index_x2a_Sl_ram1 = mct_avect_indexra(x2a,'Sl_ram1') - index_x2a_Sl_soilw = mct_avect_indexra(x2a,'Sl_soilw',perrWith='quiet') - - index_x2a_Sx_tref = mct_avect_indexra(x2a,'Sx_tref') - index_x2a_Sx_qref = mct_avect_indexra(x2a,'Sx_qref') - - index_x2a_Sf_ifrac = mct_avect_indexra(x2a,'Sf_ifrac') - index_x2a_Sf_ofrac = mct_avect_indexra(x2a,'Sf_ofrac') - index_x2a_Sf_lfrac = mct_avect_indexra(x2a,'Sf_lfrac') - - index_x2a_Sx_u10 = mct_avect_indexra(x2a,'Sx_u10') - index_x2a_Faxx_taux = mct_avect_indexra(x2a,'Faxx_taux') - index_x2a_Faxx_tauy = mct_avect_indexra(x2a,'Faxx_tauy') - index_x2a_Faxx_lat = mct_avect_indexra(x2a,'Faxx_lat') - index_x2a_Faxx_sen = mct_avect_indexra(x2a,'Faxx_sen') - index_x2a_Faxx_lwup = mct_avect_indexra(x2a,'Faxx_lwup') - index_x2a_Faxx_evap = mct_avect_indexra(x2a,'Faxx_evap') - index_x2a_So_ustar = mct_avect_indexra(x2a,'So_ustar') - index_x2a_So_re = mct_avect_indexra(x2a,'So_re') - index_x2a_So_ssq = mct_avect_indexra(x2a,'So_ssq') - index_x2a_Sl_fv = mct_avect_indexra(x2a,'Sl_fv') - index_x2a_Sl_ram1 = mct_avect_indexra(x2a,'Sl_ram1') - index_x2a_Fall_flxdst1 = mct_avect_indexra(x2a,'Fall_flxdst1') - index_x2a_Fall_flxdst2 = mct_avect_indexra(x2a,'Fall_flxdst2') - index_x2a_Fall_flxdst3 = mct_avect_indexra(x2a,'Fall_flxdst3') - index_x2a_Fall_flxdst4 = mct_avect_indexra(x2a,'Fall_flxdst4') - index_x2a_Fall_fco2_lnd = mct_avect_indexra(x2a,'Fall_fco2_lnd',perrWith='quiet') - index_x2a_Faoo_fco2_ocn = mct_avect_indexra(x2a,'Faoo_fco2_ocn',perrWith='quiet') - index_x2a_Faoo_fdms_ocn = mct_avect_indexra(x2a,'Faoo_fdms_ocn',perrWith='quiet') - - if (shr_megan_mechcomps_n>0) then - index_x2a_Fall_flxvoc = mct_avect_indexra(x2a,trim(shr_megan_fields_token)) - else - index_x2a_Fall_flxvoc = 0 - endif - - if (shr_fire_emis_mechcomps_n>0) then - index_x2a_Fall_flxfire = mct_avect_indexra(x2a,trim(shr_fire_emis_fields_token)) - index_x2a_Sl_ztopfire = mct_avect_indexra(x2a,trim(shr_fire_emis_ztop_token)) - else - index_x2a_Fall_flxfire = 0 - index_x2a_Sl_ztopfire = 0 - endif - - if ( lnd_drydep )then - index_x2a_Sl_ddvel = mct_avect_indexra(x2a, trim(drydep_fields_token)) - else - index_x2a_Sl_ddvel = 0 - end if - - index_a2x_Sa_z = mct_avect_indexra(a2x,'Sa_z') - index_a2x_Sa_topo = mct_avect_indexra(a2x,'Sa_topo') - index_a2x_Sa_u = mct_avect_indexra(a2x,'Sa_u') - index_a2x_Sa_v = mct_avect_indexra(a2x,'Sa_v') - index_a2x_Sa_tbot = mct_avect_indexra(a2x,'Sa_tbot') - index_a2x_Sa_ptem = mct_avect_indexra(a2x,'Sa_ptem') - index_a2x_Sa_pbot = mct_avect_indexra(a2x,'Sa_pbot') - index_a2x_Sa_pslv = mct_avect_indexra(a2x,'Sa_pslv') - index_a2x_Sa_shum = mct_avect_indexra(a2x,'Sa_shum') - index_a2x_Sa_dens = mct_avect_indexra(a2x,'Sa_dens') - index_a2x_Faxa_swnet = mct_avect_indexra(a2x,'Faxa_swnet') - index_a2x_Faxa_lwdn = mct_avect_indexra(a2x,'Faxa_lwdn') - index_a2x_Faxa_rainc = mct_avect_indexra(a2x,'Faxa_rainc') - index_a2x_Faxa_rainl = mct_avect_indexra(a2x,'Faxa_rainl') - index_a2x_Faxa_snowc = mct_avect_indexra(a2x,'Faxa_snowc') - index_a2x_Faxa_snowl = mct_avect_indexra(a2x,'Faxa_snowl') - index_a2x_Faxa_swndr = mct_avect_indexra(a2x,'Faxa_swndr') - index_a2x_Faxa_swvdr = mct_avect_indexra(a2x,'Faxa_swvdr') - index_a2x_Faxa_swndf = mct_avect_indexra(a2x,'Faxa_swndf') - index_a2x_Faxa_swvdf = mct_avect_indexra(a2x,'Faxa_swvdf') - index_a2x_Faxa_bcphidry = mct_avect_indexra(a2x,'Faxa_bcphidry') - index_a2x_Faxa_bcphodry = mct_avect_indexra(a2x,'Faxa_bcphodry') - index_a2x_Faxa_bcphiwet = mct_avect_indexra(a2x,'Faxa_bcphiwet') - index_a2x_Faxa_ocphidry = mct_avect_indexra(a2x,'Faxa_ocphidry') - index_a2x_Faxa_ocphodry = mct_avect_indexra(a2x,'Faxa_ocphodry') - index_a2x_Faxa_ocphiwet = mct_avect_indexra(a2x,'Faxa_ocphiwet') - index_a2x_Faxa_dstdry1 = mct_avect_indexra(a2x,'Faxa_dstdry1') - index_a2x_Faxa_dstdry2 = mct_avect_indexra(a2x,'Faxa_dstdry2') - index_a2x_Faxa_dstdry3 = mct_avect_indexra(a2x,'Faxa_dstdry3') - index_a2x_Faxa_dstdry4 = mct_avect_indexra(a2x,'Faxa_dstdry4') - index_a2x_Faxa_dstwet1 = mct_avect_indexra(a2x,'Faxa_dstwet1') - index_a2x_Faxa_dstwet2 = mct_avect_indexra(a2x,'Faxa_dstwet2') - index_a2x_Faxa_dstwet3 = mct_avect_indexra(a2x,'Faxa_dstwet3') - index_a2x_Faxa_dstwet4 = mct_avect_indexra(a2x,'Faxa_dstwet4') - index_a2x_Sa_co2prog = mct_avect_indexra(a2x,'Sa_co2prog',perrWith='quiet') - index_a2x_Sa_co2diag = mct_avect_indexra(a2x,'Sa_co2diag',perrWith='quiet') - index_a2x_Faxa_nhx = mct_avect_indexra(a2x,'Faxa_nhx',perrWith='quiet') - index_a2x_Faxa_noy = mct_avect_indexra(a2x,'Faxa_noy',perrWith='quiet') - - ! Call coupler independent interface routines to set flags for specific - ! fields so CAM can query whether they are passed by the coupler. - call set_active_Sl_ram1( index_x2a_Sl_ram1>0) - call set_active_Sl_fv( index_x2a_Sl_fv>0) - call set_active_Sl_soilw( index_x2a_Sl_soilw>0) - call set_active_Fall_flxdst1( index_x2a_Fall_flxdst1>0) - call set_active_Fall_flxvoc( index_x2a_Fall_flxvoc>0) - call set_active_Fall_flxfire( index_x2a_Fall_flxfire>0) - call set_active_Fall_fco2_lnd(index_x2a_Fall_fco2_lnd>0) - call set_active_Faoo_fco2_ocn(index_x2a_Faoo_fco2_ocn>0) - - ! Call coupler independent interface routines to set flags for specific - ! fields so CAM can query whether the coupler expects them to be provided. - call set_active_Faxa_nhx( index_a2x_Faxa_nhx>0) - call set_active_Faxa_noy( index_a2x_Faxa_noy>0) - - call mct_aVect_clean(x2a) - call mct_aVect_clean(a2x) - - end subroutine cam_cpl_indices_set - -end module cam_cpl_indices diff --git a/src/cpl/nuopc/atm_comp_nuopc.F90 b/src/cpl/nuopc/atm_comp_nuopc.F90 index 387a1660..818760eb 100644 --- a/src/cpl/nuopc/atm_comp_nuopc.F90 +++ b/src/cpl/nuopc/atm_comp_nuopc.F90 @@ -1,2326 +1,2100 @@ module atm_comp_nuopc - !---------------------------------------------------------------------------- - ! This is the NUOPC cap for CAM - !---------------------------------------------------------------------------- - - use ESMF, only: ESMF_SUCCESS, ESMF_FAILURE, ESMF_KIND_I8 - use ESMF, only: ESMF_ALARMLIST_ALL, ESMF_METHOD_INITIALIZE - use ESMF, only: ESMF_LOGMSG_INFO, ESMF_MAXSTR, ESMF_LOGERR_PASSTHRU - use ESMF, only: ESMF_FILEFORMAT_ESMFMESH, ESMF_RC_NOT_VALID - use ESMF, only: ESMF_CALKIND_NOLEAP, ESMF_CALKIND_GREGORIAN - - use ESMF, only: ESMF_STAGGERLOC_CENTER, ESMF_STAGGERLOC_CORNER - use ESMF, only: ESMF_GridCreateNoPeriDimUfrm - use ESMF, only: ESMF_GridComp, ESMF_State, ESMF_Clock, ESMF_VM - use ESMF, only: ESMF_TimeInterval, ESMF_Time, ESMF_Calendar - use ESMF, only: ESMF_Mesh, ESMF_Field, ESMF_Alarm - use ESMF, only: ESMF_CalKind_Flag, operator(==), operator(+) - - use ESMF, only: ESMF_GridCompSetEntryPoint - use ESMF, only: ESMF_MethodRemove - use ESMF, only: ESMF_VMGetCurrent, ESMF_VMGet - use ESMF, only: ESMF_Grid, ESMF_DistGrid, ESMF_GridCompGet - use ESMF, only: ESMF_ClockGet, ESMF_ClockSet, ESMF_ClockAdvance - use ESMF, only: ESMF_ClockGetAlarm, ESMF_ClockGetNextTime - use ESMF, only: ESMF_ClockGetAlarmList - use ESMF, only: ESMF_TimeGet, ESMF_TimeIntervalGet - use ESMF, only: ESMF_DistGridCreate, ESMF_MeshCreate, ESMF_MeshGet - use ESMF, only: ESMF_StateGet, ESMF_FieldGet - use ESMF, only: ESMF_AlarmIsRinging, ESMF_AlarmRingerOff, ESMF_AlarmSet - use ESMF, only: ESMF_LogWrite, ESMF_LogSetError - use ESMF, only: ESMF_LogFoundError - - use NUOPC, only: NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize - use NUOPC, only: NUOPC_CompFilterPhaseMap, NUOPC_IsUpdated, NUOPC_IsAtTime - use NUOPC, only: NUOPC_CompAttributeGet, NUOPC_Advertise - use NUOPC, only: NUOPC_SetAttribute, NUOPC_CompAttributeGet, NUOPC_CompAttributeSet - use NUOPC_Model, only: model_routine_SS => SetServices - use NUOPC_Model, only: SetVM - use NUOPC_Model, only: model_label_Advance => label_Advance - use NUOPC_Model, only: model_label_DataInitialize => label_DataInitialize - use NUOPC_Model, only: model_label_SetRunClock => label_SetRunClock - use NUOPC_Model, only: model_label_Finalize => label_Finalize - use NUOPC_Model, only: NUOPC_ModelGet - use shr_kind_mod, only: r8=>shr_kind_r8, i8=>shr_kind_i8 - use shr_kind_mod, only: CX=>shr_kind_cx, CL=>shr_kind_cl - use shr_kind_mod, only: CS=>shr_kind_cs - use shr_sys_mod, only: shr_sys_abort - use shr_file_mod, only: shr_file_getlogunit, shr_file_setlogunit - use shr_cal_mod, only: shr_cal_noleap, shr_cal_gregorian, shr_cal_ymd2date - use shr_const_mod, only: shr_const_pi - use shr_orb_mod, only: shr_orb_decl, shr_orb_params, SHR_ORB_UNDEF_REAL, SHR_ORB_UNDEF_INT - use cam_instance, only: cam_instance_init, inst_suffix, inst_index -! use radiation, only: radiation_nextsw_cday, rad_nextsw_cday=>nextsw_cday - use camsrfexch, only: cam_out_t, cam_in_t - use cam_logfile, only: cam_set_log_unit, iulog - use spmd_utils, only: spmd_init, masterproc, iam, mpicom - use time_manager, only: get_curr_calday, advance_timestep, get_curr_date, get_nstep, get_step_size - use atm_import_export, only: advertise_fields, realize_fields - use atm_import_export, only: import_fields, export_fields - use nuopc_shr_methods, only: chkerr, state_setscalar, state_getscalar, state_diagnose, alarmInit - use nuopc_shr_methods, only: set_component_logging, get_component_instance, log_clock_advance - use perf_mod, only: t_startf, t_stopf - use physics_grid, only: columns_on_task, global_index_p, get_rlon_all_p, get_rlat_all_p - use physics_grid, only: num_global_phys_cols, get_grid_dims - use cam_control_mod, only: cam_ctrl_set_orbit - use cam_pio_utils, only: cam_pio_createfile, cam_pio_openfile, cam_pio_closefile, cam_pio_newdecomp - use cam_initfiles, only: cam_initfiles_get_caseid, cam_initfiles_get_restdir - use filenames, only: interpret_filename_spec - use pio, only: file_desc_t, io_desc_t, var_desc_t, pio_double, pio_def_dim, PIO_MAX_NAME - use pio, only: pio_freedecomp - use pio, only: pio_closefile, pio_inq_varid, pio_put_att, pio_enddef - use pio, only: pio_read_darray, pio_write_darray, pio_def_var, pio_inq_varid - use pio, only: pio_noerr, pio_bcast_error, pio_internal_error, pio_seterrorhandling - use pio, only: pio_def_var, pio_put_var, PIO_INT, PIO_OFFSET_KIND - !$use omp_lib, only: omp_set_num_threads - - implicit none - private ! except - - public :: SetServices - public :: SetVM - !-------------------------------------------------------------------------- - ! Private interfaces - !-------------------------------------------------------------------------- - - private :: InitializeP0 - private :: InitializeAdvertise - private :: InitializeRealize - private :: ModelAdvance - private :: ModelSetRunClock - private :: ModelFinalize - private :: cam_read_srfrest - private :: cam_write_srfrest - private :: cam_orbital_init - private :: cam_orbital_update - private :: cam_set_mesh_for_single_column - - !-------------------------------------------------------------------------- - ! Private module data - !-------------------------------------------------------------------------- - - character(len=CL) :: flds_scalar_name = '' - integer :: flds_scalar_num = 0 - integer :: flds_scalar_index_nx = 0 - integer :: flds_scalar_index_ny = 0 - integer :: flds_scalar_index_nextsw_cday = 0 - - integer, parameter :: dbug_flag = 0 - - ! Remove "NULL" once cam_in/out are fully developed -JN: - type(cam_in_t), pointer :: cam_in => NULL() - type(cam_out_t), pointer :: cam_out => NULL() - - character(len=CL) :: rsfilename_spec_cam ! Filename specifier for restart surface file - character(len=*), parameter :: modName = "(atm_comp_nuopc)" - character(len=*), parameter :: u_FILE_u = __FILE__ - - logical :: dart_mode = .false. - logical :: mediator_present - - character(len=CL) :: orb_mode ! orbital mode - integer :: orb_iyear ! orbital year - integer :: orb_iyear_align ! associated with model year - real(R8) :: orb_obliq ! obliquity in degrees - real(R8) :: orb_mvelp ! moving vernal equinox longitude - real(R8) :: orb_eccen ! orbital eccentricity - - character(len=*), parameter :: orb_fixed_year = 'fixed_year' - character(len=*), parameter :: orb_variable_year = 'variable_year' - character(len=*), parameter :: orb_fixed_parameters = 'fixed_parameters' - - !Remove once history output is developed for CAMDEN -JN: - real(r8) :: fillvalue = 9.87e36_r8 - - real(R8), parameter :: grid_tol = 1.e-2_r8 ! tolerance for calculated lat/lon vs read in - integer :: local_iulog = 6 !Local iulog for use with NUOPC interfaces - - ! dof is the global index space decomposition - integer(kind=PIO_OFFSET_KIND), allocatable :: dof(:) - -!========================================================================== -CONTAINS -!========================================================================== - - subroutine SetServices(gcomp, rc) - type(ESMF_GridComp) :: gcomp - integer, intent(out) :: rc - - ! local variables - character(len=*), parameter :: subname=trim(modName)//':(SetServices) ' - - rc = ESMF_SUCCESS - - ! the NUOPC gcomp component will register the generic methods - - call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! switching to Initialize Phase Definition (IPD) - call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & - userRoutine=InitializeP0, phase=0, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! set entry point for methods that require specific implementation - - call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & - phaseLabelList=(/"IPDv03p1"/), userRoutine=InitializeAdvertise, & - rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & - phaseLabelList=(/"IPDv03p3"/), userRoutine=InitializeRealize, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! attach specializing method(s) - - call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, & - specRoutine=ModelAdvance, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call NUOPC_CompSpecialize(gcomp, specLabel=model_label_DataInitialize, & - specRoutine=DataInitialize, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, & - specRoutine=ModelSetRunClock, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, & - specRoutine=ModelFinalize, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - end subroutine SetServices - - !========================================================================== - subroutine InitializeP0(gcomp, importState, exportState, clock, rc) - type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: importState, exportState - type(ESMF_Clock) :: clock - integer, intent(out) :: rc - !------------------------------------------------------------------------ - rc = ESMF_SUCCESS - - ! Switch to IPDv03 by filtering all other phaseMap entries - call NUOPC_CompFilterPhaseMap(gcomp, ESMF_METHOD_INITIALIZE, & - acceptStringList=(/"IPDv03p"/), rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - end subroutine InitializeP0 - - !========================================================================== - subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) - - ! Dummy arguments - type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: importState, exportState - type(ESMF_Clock) :: clock - integer, intent(out) :: rc - - ! Local variables - type(ESMF_VM) :: vm - integer :: n - integer :: localpet - character(len=CL) :: cvalue - character(len=CL) :: logmsg - logical :: isPresent, isSet - integer :: shrlogunit ! original log unit - character(len=*), parameter :: subname=trim(modName)//':(InitializeAdvertise) ' - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - if (dbug_flag > 5) then - call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) - end if - - call ESMF_VMGetCurrent(vm, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call ESMF_VmGet(vm, localPet=localPet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - !----------------------------------------------------------------------- - ! reset shr logging to my log file - !----------------------------------------------------------------------- - - call set_component_logging(gcomp, localpet==0, local_iulog, & - shrlogunit, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call shr_file_setLogUnit (shrlogunit) - call cam_set_log_unit(local_iulog) - - !----------------------------------------------------------------------- - ! advertise import/export fields - !----------------------------------------------------------------------- - - call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldName", & - value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (isPresent .and. isSet) then - flds_scalar_name = trim(cvalue) - call ESMF_LogWrite(trim(subname)//' flds_scalar_name = '// & - trim(flds_scalar_name), ESMF_LOGMSG_INFO) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call shr_sys_abort(subname//'Need to set attribute ScalarFieldName') - end if - - call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldCount", & - value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (isPresent .and. isSet) then - read(cvalue, *) flds_scalar_num - write(logmsg,*) flds_scalar_num - call ESMF_LogWrite(trim(subname)//' flds_scalar_num = '// & - trim(logmsg), ESMF_LOGMSG_INFO) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call shr_sys_abort(subname//'Need to set attribute ScalarFieldCount') - end if - - call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNX", & - value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (isPresent .and. isSet) then - read(cvalue,*) flds_scalar_index_nx - write(logmsg,*) flds_scalar_index_nx - call ESMF_LogWrite(trim(subname)//' : flds_scalar_index_nx = '// & - trim(logmsg), ESMF_LOGMSG_INFO) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call shr_sys_abort(subname// & - 'Need to set attribute ScalarFieldIdxGridNX') - end if - - call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNY", & - value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (isPresent .and. isSet) then - read(cvalue,*) flds_scalar_index_ny - write(logmsg,*) flds_scalar_index_ny - call ESMF_LogWrite(trim(subname)//' : flds_scalar_index_ny = '// & - trim(logmsg), ESMF_LOGMSG_INFO) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call shr_sys_abort(subname// & - 'Need to set attribute ScalarFieldIdxGridNY') - end if - - call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxNextSwCday", & - value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (isPresent .and. isSet) then - read(cvalue,*) flds_scalar_index_nextsw_cday - write(logmsg,*) flds_scalar_index_nextsw_cday - call ESMF_LogWrite(trim(subname)// & - ' : flds_scalar_index_nextsw_cday = '//trim(logmsg), & - ESMF_LOGMSG_INFO) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call shr_sys_abort(subname// & - 'Need to set attribute ScalarFieldIdxNextSwCday') - end if - - call NUOPC_CompAttributeGet(gcomp, name="mediator_present", & - value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (isPresent .and. isSet) then - read (cvalue,*) mediator_present - if (mediator_present) then - call advertise_fields(gcomp, flds_scalar_name, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - else - call shr_sys_abort(subname//'Need to set attribute mediator_present') - end if - - if (dbug_flag > 5) then - call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) - end if - end subroutine InitializeAdvertise - - !========================================================================== - subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) - - use string_utils, only: to_str - use cam_comp, only: cam_init - - ! Dummy arguments - type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: importState - type(ESMF_State) :: exportState - type(ESMF_Clock) :: clock - integer, intent(out) :: rc - - ! Local variables - type(ESMF_VM) :: vm - type(ESMF_Time) :: currTime ! Current time - type(ESMF_Time) :: startTime ! Start time - type(ESMF_Time) :: stopTime ! Stop time - type(ESMF_Time) :: refTime ! Ref time - type(ESMF_TimeInterval) :: timeStep - type(ESMF_CalKind_Flag) :: esmf_caltype ! esmf calendar type - type(ESMF_DistGrid) :: distGrid - type(ESMF_Mesh) :: mesh, Emesh - integer :: spatialDim - integer :: numOwnedElements - real(R8), pointer :: ownedElemCoords(:) - real(r8), pointer :: lat(:), latMesh(:) - real(r8), pointer :: lon(:), lonMesh(:) - real(r8) :: lats(columns_on_task) ! array of task latitudes - real(r8) :: lons(columns_on_task) ! array of taskk longitude - integer :: hdim1_d, hdim2_d ! dims of rect horizontal grid data (If 1D data struct, hdim2_d==1) - integer :: ncols ! number of local columns - integer :: start_ymd ! Start date (YYYYMMDD) - integer :: start_tod ! Start time of day (sec) - integer :: curr_ymd ! Start date (YYYYMMDD) - integer :: curr_tod ! Start time of day (sec) - integer :: stop_ymd ! Stop date (YYYYMMDD) - integer :: stop_tod ! Stop time of day (sec) - integer :: ref_ymd ! Reference date (YYYYMMDD) - integer :: ref_tod ! Reference time of day (sec) - character(len=cs) :: calendar ! Calendar type - integer :: dtime ! time step increment (sec) - integer :: atm_cpl_dt ! driver atm coupling time step - integer :: nstep ! CAM nstep - real(r8) :: caldayp1 ! CAM calendar day for for next cam time step - integer :: yy,mm,dd ! Temporaries for time query - logical :: perpetual_run ! If in perpetual mode or not - integer :: perpetual_ymd ! Perpetual date (YYYYMMDD) - character(CL) :: cvalue - character(ESMF_MAXSTR) :: convCIM, purpComp - integer :: lsize ! local size ofarrays - integer :: n,c,g,i,j ! indices - character(len=cs) :: start_type ! infodata start type - character(len=cl) :: caseid ! case ID - character(len=cl) :: ctitle ! case title - character(len=cl) :: model_doi_url ! DOI for CESM model run - logical :: aqua_planet ! Flag to run model in "aqua planet" mode - logical :: brnch_retain_casename ! true => branch run has same caseid as run being branched from - logical :: single_column - character(len=cl) :: single_column_lnd_domainfile - real(r8) :: scol_lon - real(r8) :: scol_lat - real(r8) :: scol_spval - real(r8) :: eccen - real(r8) :: obliqr - real(r8) :: lambm0 - real(r8) :: mvelpp - logical :: dart_mode_in - !character(len=cl) :: atm_resume_all_inst(num_inst_atm) ! atm resume file - integer :: lbnum - character(CS) :: inst_name - integer :: inst_index - character(CS) :: inst_suffix - integer :: lmpicom - logical :: isPresent - character(len=CX) :: diro - character(len=CX) :: logfile - integer :: compid ! component id - integer :: localPet, localPeCount - integer :: nthrds - integer :: astat - logical :: initial_run ! startup mode which only requires a minimal initial file - logical :: restart_run ! continue a previous run; requires a restart file - logical :: branch_run ! branch from a previous run; requires a restart file - character(len=CL) :: tempc1,tempc2 - integer :: shrlogunit ! original log unit - real(r8), parameter :: radtodeg = 180.0_r8/shr_const_pi - integer, parameter :: aqua_perpetual_ymd = 321 - character(len=*), parameter :: subname=trim(modName)//':(InitializeRealize) ' - character(len=*), parameter :: format = "('("//trim(subname)//") :',A)" - !------------------------------------------------------------------------ - - rc = ESMF_SUCCESS - single_column = .false. - if (dbug_flag > 5) then - call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) - end if - - call shr_file_setLogUnit (iulog) - - !----------------------------------------------------------------------- - ! generate local mpi comm - !----------------------------------------------------------------------- - - call ESMF_GridCompGet(gcomp, vm=vm, localpet=localPet, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_VMGet(vm, mpiCommunicator=lmpicom, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - - call ESMF_VMGet(vm, pet=localPet, peCount=localPeCount, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - - if(localPeCount == 1) then - call NUOPC_CompAttributeGet(gcomp, "nthreads", value=cvalue, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=u_FILE_u)) return - read(cvalue,*) nthrds - else - nthrds = localPeCount - end if - - !$ call omp_set_num_threads(nthrds) - - !----------------------------------------------------------------------- - ! determine instance information - !----------------------------------------------------------------------- - call get_component_instance(gcomp, inst_suffix, inst_index, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - inst_name = 'ATM'//inst_suffix - ! Set filename specifier for restart surface file - ! (%c=caseid, $y=year, $m=month, $d=day, $s=seconds in day) - rsfilename_spec_cam = '%c.cam' //trim(inst_suffix)//'.rs.%y-%m-%d-%s.nc' - - !----------------------------------------------------------------------- - ! initialize cam mpi (needed for masterproc below) - !----------------------------------------------------------------------- - - call spmd_init(lmpicom) - - !----------------------------------------------------------------------- - ! Initialize cam - needed in realize phase to get grid information - !----------------------------------------------------------------------- - - call NUOPC_CompAttributeGet(gcomp, name='MCTID', value=cvalue, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=u_FILE_u)) return - read(cvalue,*) compid - call cam_instance_init(compid, inst_name, inst_index, inst_suffix) - - !----------------------------------------------------------------------- - ! Initialize cam - needed in realize phase to get grid information - !----------------------------------------------------------------------- - - if (masterproc) then - write(iulog,format) "CAM atm model initialization" - end if + !---------------------------------------------------------------------------- + ! This is the NUOPC cap for CAM + !---------------------------------------------------------------------------- + + use ESMF , only : operator(<=), operator(>), operator(==), operator(+) + use ESMF , only : ESMF_MethodRemove + use ESMF , only : ESMF_GridComp, ESMF_GridCompGet, ESMF_State, ESMF_StateGet + use ESMF , only : ESMF_Grid, ESMF_GridCreateNoPeriDimUfrm, ESMF_Field, ESMF_FieldGet + use ESMF , only : ESMF_DistGrid, ESMF_DistGridCreate + use ESMF , only : ESMF_Mesh, ESMF_MeshCreate, ESMF_MeshGet, ESMF_FILEFORMAT_ESMFMESH + use ESMF , only : ESMF_Clock, ESMF_ClockGet, ESMF_ClockSet, ESMF_ClockGetNextTime, ESMF_ClockAdvance + use ESMF , only : ESMF_Time, ESMF_TimeGet + use ESMF , only : ESMF_Alarm, ESMF_ClockGetAlarm, ESMF_AlarmRingerOff, ESMF_AlarmIsRinging + use ESMF , only : ESMF_ClockGetAlarmList, ESMF_ALARMLIST_ALL, ESMF_AlarmSet + use ESMF , only : ESMF_TimeInterval, ESMF_TimeIntervalGet + use ESMF , only : ESMF_CalKind_Flag, ESMF_MAXSTR, ESMF_KIND_I8 + use ESMF , only : ESMF_CALKIND_NOLEAP, ESMF_CALKIND_GREGORIAN + use ESMF , only : ESMF_GridCompSetEntryPoint + use ESMF , only : ESMF_VM, ESMF_VMGetCurrent, ESMF_VMGet + use ESMF , only : ESMF_LOGMSG_INFO, ESMF_LOGERR_PASSTHRU + use ESMF , only : ESMF_LogWrite, ESMF_LogSetError, ESMF_LogFoundError + use ESMF , only : ESMF_SUCCESS, ESMF_METHOD_INITIALIZE, ESMF_FAILURE, ESMF_RC_NOT_VALID + use ESMF , only : ESMF_STAGGERLOC_CENTER, ESMF_STAGGERLOC_CORNER + use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize + use NUOPC , only : NUOPC_CompFilterPhaseMap, NUOPC_IsUpdated, NUOPC_IsAtTime + use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise + use NUOPC , only : NUOPC_SetAttribute, NUOPC_CompAttributeGet, NUOPC_CompAttributeSet + use NUOPC_Model , only : model_routine_SS => SetServices + use NUOPC_Model , only : SetVM + use NUOPC_Model , only : model_label_Advance => label_Advance + use NUOPC_Model , only : model_label_DataInitialize => label_DataInitialize + use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock + use NUOPC_Model , only : model_label_Finalize => label_Finalize + use NUOPC_Model , only : NUOPC_ModelGet + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_log_mod , only : shr_log_getlogunit, shr_log_setlogunit + use shr_cal_mod , only : shr_cal_noleap, shr_cal_gregorian, shr_cal_ymd2date + use shr_const_mod , only : shr_const_pi + use shr_orb_mod , only : shr_orb_decl, shr_orb_params, SHR_ORB_UNDEF_REAL, SHR_ORB_UNDEF_INT + use cam_instance , only : cam_instance_init, inst_suffix, inst_index + use cam_comp , only : cam_init, cam_run1, cam_run2, cam_run3, cam_run4, cam_final + use cam_comp , only : cam_timestep_init, cam_timestep_final + use camsrfexch , only : cam_out_t, cam_in_t +! use radiation , only : nextsw_cday !uncomment once radiation has been CCPP-ized -JN + use cam_logfile , only : cam_set_log_unit, iulog + use cam_abortutils , only : check_allocate + use spmd_utils , only : spmd_init, masterproc, iam + use time_manager , only : get_curr_calday, advance_timestep, get_curr_date, get_nstep, get_step_size + use atm_import_export , only : read_surface_fields_namelists, advertise_fields, realize_fields + use atm_import_export , only : import_fields, export_fields + use nuopc_shr_methods , only : chkerr, state_setscalar, state_getscalar, state_diagnose, alarmInit + use nuopc_shr_methods , only : set_component_logging, get_component_instance, log_clock_advance + use perf_mod , only : t_startf, t_stopf + use physics_grid , only : global_index_p, get_rlon_all_p, get_rlat_all_p + use physics_grid , only : ngcols => num_global_phys_cols + use physics_grid , only : lsize => columns_on_task + use physics_grid , only : hdim1_d, hdim2_d + use cam_control_mod , only : cam_ctrl_set_orbit + use cam_pio_utils , only : cam_pio_createfile, cam_pio_openfile, cam_pio_closefile, pio_subsystem + use cam_initfiles , only : cam_initfiles_get_caseid, cam_initfiles_get_restdir + use filenames , only : interpret_filename_spec + use pio , only : file_desc_t, io_desc_t, var_desc_t, pio_double, pio_def_dim, PIO_MAX_NAME + use pio , only : pio_closefile, pio_put_att, pio_enddef, pio_nowrite + use pio , only : pio_inq_dimid, pio_inq_varid, pio_inquire_dimension, pio_def_var + use pio , only : pio_initdecomp, pio_freedecomp + use pio , only : pio_read_darray, pio_write_darray + use pio , only : pio_noerr, pio_bcast_error, pio_internal_error, pio_seterrorhandling + use pio , only : pio_def_var, pio_get_var, pio_put_var, PIO_INT + use ioFileMod , only : cam_get_file + !$use omp_lib , only : omp_set_num_threads + + implicit none + private ! except + + public :: SetServices + public :: SetVM + + !-------------------------------------------------------------------------- + ! Private interfaces + !-------------------------------------------------------------------------- + + private :: InitializeP0 + private :: InitializeAdvertise + private :: InitializeRealize + private :: ModelAdvance + private :: ModelSetRunClock + private :: ModelFinalize + private :: cam_read_srfrest + private :: cam_write_srfrest + private :: cam_orbital_init + private :: cam_orbital_update + private :: cam_set_mesh_for_single_column + private :: cam_pio_checkerr + + !-------------------------------------------------------------------------- + ! Private module data + !-------------------------------------------------------------------------- + + character(len=CL) :: flds_scalar_name = '' + integer :: flds_scalar_num = 0 + integer :: flds_scalar_index_nx = 0 + integer :: flds_scalar_index_ny = 0 + integer :: flds_scalar_index_nextsw_cday = 0 + integer :: nthrds + integer :: ierr ! allocate status + integer , parameter :: dbug_flag = 0 + type(cam_in_t) , pointer :: cam_in + type(cam_out_t) , pointer :: cam_out + integer , pointer :: dof(:) ! global index space decomposition + character(len=256) :: rsfilename_spec_cam ! Filename specifier for restart surface file + character(*) ,parameter :: modName = "(atm_comp_nuopc)" + character(*) ,parameter :: u_FILE_u = & + __FILE__ + + logical :: dart_mode = .false. + logical :: mediator_present + + character(len=CL) :: orb_mode ! attribute - orbital mode + integer :: orb_iyear ! attribute - orbital year + integer :: orb_iyear_align ! attribute - associated with model year + real(R8) :: orb_obliq ! attribute - obliquity in degrees + real(R8) :: orb_mvelp ! attribute - moving vernal equinox longitude + real(R8) :: orb_eccen ! attribute and update- orbital eccentricity + + character(len=*) , parameter :: orb_fixed_year = 'fixed_year' + character(len=*) , parameter :: orb_variable_year = 'variable_year' + character(len=*) , parameter :: orb_fixed_parameters = 'fixed_parameters' + + !Remove once history output is developed for CAMDEN -JN: + real(r8), parameter :: fillvalue = 1.e36_r8 + + real(R8) , parameter :: grid_tol = 1.e-2_r8 ! tolerance for calculated lat/lon vs read in + + type(ESMF_Mesh) :: model_mesh ! model_mesh + type(ESMF_Clock) :: model_clock ! model_clock + +!=============================================================================== +contains +!=============================================================================== + + subroutine SetServices(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + character(len=*),parameter :: subname=trim(modName)//':(SetServices) ' + + rc = ESMF_SUCCESS + + ! the NUOPC gcomp component will register the generic methods + + call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! switching to IPD version v03 + + call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + userRoutine=InitializeP0, phase=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! set entry point for methods that require specific implementation + + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv03p1"/), userRoutine=InitializeAdvertise, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, & + phaseLabelList=(/"IPDv03p3"/), userRoutine=InitializeRealize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! attach specializing method(s) + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Advance, & + specRoutine=ModelAdvance, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_DataInitialize, & + specRoutine=DataInitialize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_MethodRemove(gcomp, label=model_label_SetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_SetRunClock, & + specRoutine=ModelSetRunClock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, & + specRoutine=ModelFinalize, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine SetServices + + !=============================================================================== + subroutine InitializeP0(gcomp, importState, exportState, clock, rc) + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Switch to IPDv03 by filtering all other phaseMap entries + call NUOPC_CompFilterPhaseMap(gcomp, ESMF_METHOD_INITIALIZE, acceptStringList=(/"IPDv03p"/), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine InitializeP0 + + !=============================================================================== + subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + + ! intput/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState, exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_VM) :: vm + integer :: n + integer :: localpet + character(len=CL) :: cvalue + character(len=CL) :: logmsg + logical :: isPresent, isSet + integer :: shrlogunit ! original log unit + integer :: newlogunit ! new log unit + character(len=*), parameter :: subname=trim(modName)//':(InitializeAdvertise) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + if (dbug_flag > 5) then + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + end if + + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VmGet(vm, localPet=localPet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------------------------------------------------------------------- + ! reset shr logging to my log file + !---------------------------------------------------------------------------- + + call set_component_logging(gcomp, localpet==0, newlogunit, shrlogunit, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call shr_log_setLogUnit(newlogunit) + !Set CAM-SIMA log unit to new unit value: + call cam_set_log_unit(newlogunit) + + !---------------------------------------------------------------------------- + ! advertise import/export fields + !---------------------------------------------------------------------------- + + call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldName", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + flds_scalar_name = trim(cvalue) + call ESMF_LogWrite(trim(subname)//' flds_scalar_name = '//trim(flds_scalar_name), ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call shr_sys_abort(subname//'Need to set attribute ScalarFieldName') + endif + + call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldCount", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue, *) flds_scalar_num + write(logmsg,*) flds_scalar_num + call ESMF_LogWrite(trim(subname)//' flds_scalar_num = '//trim(logmsg), ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call shr_sys_abort(subname//'Need to set attribute ScalarFieldCount') + endif + + call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNX", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue,*) flds_scalar_index_nx + write(logmsg,*) flds_scalar_index_nx + call ESMF_LogWrite(trim(subname)//' : flds_scalar_index_nx = '//trim(logmsg), ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call shr_sys_abort(subname//'Need to set attribute ScalarFieldIdxGridNX') + endif + + call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxGridNY", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue,*) flds_scalar_index_ny + write(logmsg,*) flds_scalar_index_ny + call ESMF_LogWrite(trim(subname)//' : flds_scalar_index_ny = '//trim(logmsg), ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call shr_sys_abort(subname//'Need to set attribute ScalarFieldIdxGridNY') + endif + + call NUOPC_CompAttributeGet(gcomp, name="ScalarFieldIdxNextSwCday", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue,*) flds_scalar_index_nextsw_cday + write(logmsg,*) flds_scalar_index_nextsw_cday + call ESMF_LogWrite(trim(subname)//' : flds_scalar_index_nextsw_cday = '//trim(logmsg), ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call shr_sys_abort(subname//'Need to set attribute ScalarFieldIdxNextSwCday') + endif + + ! read mediator fields namelists + call read_surface_fields_namelists() + + call NUOPC_CompAttributeGet(gcomp, name="mediator_present", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read (cvalue,*) mediator_present + if (mediator_present) then + call advertise_fields(gcomp, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + else + call shr_sys_abort(subname//'Need to set attribute mediator_present') + endif + + if (dbug_flag > 5) then + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + end if + end subroutine InitializeAdvertise + + !=============================================================================== + subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) + + use ESMF, only : ESMF_VMGet + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_State) :: importState + type(ESMF_State) :: exportState + type(ESMF_Clock) :: clock + integer, intent(out) :: rc + + ! local variables + type(ESMF_VM) :: vm + type(ESMF_Time) :: currTime ! Current time + type(ESMF_Time) :: startTime ! Start time + type(ESMF_Time) :: stopTime ! Stop time + type(ESMF_Time) :: refTime ! Ref time + type(ESMF_TimeInterval) :: timeStep + type(ESMF_CalKind_Flag) :: esmf_caltype ! esmf calendar type + type(ESMF_DistGrid) :: distGrid + integer :: spatialDim + integer :: numOwnedElements + real(r8), allocatable :: ownedElemCoords(:) + real(r8) :: lat(lsize) + real(r8) :: latMesh(lsize) + real(r8) :: lon(lsize) + real(r8) :: lonMesh(lsize) + integer :: ncols ! number of local columns + integer :: start_ymd ! Start date (YYYYMMDD) + integer :: start_tod ! Start time of day (sec) + integer :: curr_ymd ! Start date (YYYYMMDD) + integer :: curr_tod ! Start time of day (sec) + integer :: stop_ymd ! Stop date (YYYYMMDD) + integer :: stop_tod ! Stop time of day (sec) + integer :: ref_ymd ! Reference date (YYYYMMDD) + integer :: ref_tod ! Reference time of day (sec) + character(len=cs) :: calendar ! Calendar type + integer :: dtime ! time step increment (sec) + integer :: atm_cpl_dt ! driver atm coupling time step + integer :: nstep ! CAM nstep + real(r8) :: caldayp1 ! CAM calendar day for for next cam time step + integer :: yy,mm,dd ! Temporaries for time query + logical :: perpetual_run ! If in perpetual mode or not + integer :: perpetual_ymd ! Perpetual date (YYYYMMDD) + character(CL) :: cvalue + character(ESMF_MAXSTR) :: convCIM, purpComp + integer :: n,c,g,i,j ! indices + character(len=cs) :: start_type ! infodata start type + character(len=cl) :: caseid ! case ID + character(len=cl) :: ctitle ! case title + character(len=cl) :: model_doi_url ! DOI for CESM model run + logical :: aqua_planet ! Flag to run model in "aqua planet" mode + logical :: brnch_retain_casename ! true => branch run has same caseid as run being branched from + logical :: single_column = .false. + character(len=cl) :: single_column_lnd_domainfile + real(r8) :: scol_lon + real(r8) :: scol_lat + real(r8) :: scol_spval + real(r8) :: eccen + real(r8) :: obliqr + real(r8) :: lambm0 + real(r8) :: mvelpp + !character(len=cl) :: atm_resume_all_inst(num_inst_atm) ! atm resume file + integer :: lbnum + character(CS) :: inst_name + integer :: inst_index + character(CS) :: inst_suffix + integer :: lmpicom + logical :: isPresent, isSet + character(len=512) :: diro + character(len=512) :: logfile + integer :: compid ! component id + integer :: localPet, localPeCount + logical :: initial_run ! startup mode which only requires a minimal initial file + logical :: restart_run ! continue a previous run; requires a restart file + logical :: branch_run ! branch from a previous run; requires a restart file + character(len=CL) :: tempc1,tempc2 + integer :: shrlogunit ! original log unit + real(r8) , parameter :: radtodeg = 180.0_r8/shr_const_pi + integer , parameter :: aqua_perpetual_ymd = 321 + character(len=*), parameter :: subname=trim(modName)//':(InitializeRealize) ' + character(len=*), parameter :: format = "('("//trim(subname)//") :',A)" + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + if (dbug_flag > 5) then + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + end if + + call shr_log_setLogUnit (iulog) + + !---------------------------------------------------------------------------- + ! generate local mpi comm + !---------------------------------------------------------------------------- + + call ESMF_GridCompGet(gcomp, vm=vm, localpet=localPet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMGet(vm, mpiCommunicator=lmpicom, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMGet(vm, pet=localPet, peCount=localPeCount, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + if(localPeCount == 1) then + call NUOPC_CompAttributeGet(gcomp, "nthreads", value=cvalue, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return + read(cvalue,*) nthrds + else + nthrds = localPeCount + endif + +!$ call omp_set_num_threads(nthrds) + + !---------------------------------------------------------------------------- + ! determine instance information + !---------------------------------------------------------------------------- + call get_component_instance(gcomp, inst_suffix, inst_index, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + inst_name = 'ATM'//inst_suffix + ! Set filename specifier for restart surface file + ! (%c=caseid, $y=year, $m=month, $d=day, $s=seconds in day) + rsfilename_spec_cam = '%c.cam' // trim(inst_suffix) // '.rs.%y-%m-%d-%s.nc' + + !---------------------------------------------------------------------------- + ! initialize cam mpi (needed for masterproc below) + !---------------------------------------------------------------------------- + + call spmd_init(lmpicom) + + !---------------------- + ! Initialize cam - needed in realize phase to get grid information + !---------------------- + + call NUOPC_CompAttributeGet(gcomp, name='MCTID', value=cvalue, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return + read(cvalue,*) compid + call cam_instance_init(compid, inst_name, inst_index, inst_suffix) + + !---------------------- + ! Initialize cam - needed in realize phase to get grid information + !---------------------- + + if (masterproc) then + write(iulog,format) "CAM atm model initialization" + end if #if (defined _MEMTRACE) - if(masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out','atm_comp_nuopc_InitializeRealize:start::',lbnum) - end if + if(masterproc) then + lbnum=1 + call memmon_dump_fort('memmon.out','atm_comp_nuopc_InitializeRealize:start::',lbnum) + endif #endif - !---------------------- - ! Obtain and load orbital values - !---------------------- - - call cam_orbital_init(gcomp, iulog, masterproc, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call cam_orbital_update(clock, iulog, masterproc, eccen, obliqr, & - lambm0, mvelpp, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call cam_ctrl_set_orbit(eccen, obliqr, lambm0, mvelpp) - - !---------------------- - ! Obtain attributes - !---------------------- - - call NUOPC_CompAttributeGet(gcomp, name='case_name', value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) caseid - ctitle=caseid - - ! starting info - call NUOPC_CompAttributeGet(gcomp, name='start_type', value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) start_type - call NUOPC_CompAttributeGet(gcomp, name='brnch_retain_casename', & - value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) brnch_retain_casename - - ! single column input - call NUOPC_CompAttributeGet(gcomp, name='scol_lon', value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) scol_lon - call NUOPC_CompAttributeGet(gcomp, name='scol_lat', value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) scol_lat - call NUOPC_CompAttributeGet(gcomp, name='scol_spval', value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) scol_spval - call NUOPC_CompAttributeGet(gcomp, name='single_column_lnd_domainfile', & - value=single_column_lnd_domainfile, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (scol_lon > scol_spval .and. scol_lat > scol_spval) then - if (trim(single_column_lnd_domainfile) /= 'UNSET') then - single_column = .true. - else - call shr_sys_abort(subname// & - 'single_column_lnd_domainfile cannot be null for single column mode') - end if - else - single_column = .false. - end if - - ! aqua planet input - call NUOPC_CompAttributeGet(gcomp, name='aqua_planet', & - value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) aqua_planet - - ! perpetual input - call NUOPC_CompAttributeGet(gcomp, name='perpetual', value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) perpetual_run - call NUOPC_CompAttributeGet(gcomp, name='perpetual_ymd', & - value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) perpetual_ymd - - ! TODO: query the config attributes for the number of instances - ! ASSUMES multi-driver - - ! TODO: must obtain model_doi_url from gcomp - for now hardwire to - ! 'not_set' - model_doi_url = 'not_set' - - ! TODO: obtain dart_mode as a attribute variable - ! DART always starts up as an initial run. - if (dart_mode) then - initial_run = .true. - restart_run = .false. - branch_run = .false. - end if - - ! Initialize CAM, allocate cam_in and cam_out and determine - ! atm decomposition (needed to initialize gsmap) - ! for an initial run, cam_in and cam_out are allocated in cam_init - ! for a restart/branch run, cam_in and cam_out are allocated in restart - ! - !TODO: the following strings must not be hard-wired - must have module variables - ! like seq_infodata_start_type_type - maybe another entry in flds_mod? - - initial_run = .false. - restart_run = .false. - branch_run = .false. - if (trim(start_type) == trim('startup')) then - initial_run = .true. - else if (trim(start_type) == trim('continue')) then - restart_run = .true. - else if (trim(start_type) == trim('branch')) then - branch_run = .true. - else - call shr_sys_abort(subname//' ERROR: unknown start_type') - end if - - ! Get properties from clock - call ESMF_ClockGet(clock, & - currTime=currTime, startTime=startTime, stopTime=stopTime, & - refTime=RefTime, timeStep=timeStep, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_TimeGet(currTime, yy=yy, mm=mm, dd=dd, s=curr_tod, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call shr_cal_ymd2date(yy,mm,dd,curr_ymd) - - call ESMF_TimeGet(startTime, yy=yy, mm=mm, dd=dd, s=start_tod, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call shr_cal_ymd2date(yy,mm,dd,start_ymd) - - call ESMF_TimeGet(stopTime, yy=yy, mm=mm, dd=dd, s=stop_tod, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call shr_cal_ymd2date(yy,mm,dd,stop_ymd) - - call ESMF_TimeGet(refTime, yy=yy, mm=mm, dd=dd, s=ref_tod, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call shr_cal_ymd2date(yy,mm,dd,ref_ymd) - - call ESMF_TimeIntervalGet(timeStep, s=dtime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_TimeGet(currTime, calkindflag=esmf_caltype, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - if (esmf_caltype == ESMF_CALKIND_NOLEAP) then - calendar = shr_cal_noleap - else if (esmf_caltype == ESMF_CALKIND_GREGORIAN) then - calendar = shr_cal_gregorian - else - call shr_sys_abort(subname//'ERROR:: bad calendar for ESMF') - end if - - ! Initialize module orbital values and update orbital - - call cam_orbital_init(gcomp, iulog, masterproc, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call cam_orbital_update(clock, iulog, masterproc, eccen, obliqr, & - lambm0, mvelpp, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! Initialize CAM - if (aqua_planet) then - perpetual_run = .true. - perpetual_ymd = aqua_perpetual_ymd - end if - - call cam_init( & - caseid=caseid, ctitle=ctitle, model_doi_url=model_doi_url, & - initial_run_in=initial_run, restart_run_in=restart_run, & - branch_run_in=branch_run, & -! post_assim_in=dart_mode, & - calendar=calendar, brnch_retain_casename=brnch_retain_casename, & - aqua_planet=aqua_planet, & - single_column=single_column, scmlat=scol_lat, scmlon=scol_lon, & - eccen=eccen, obliqr=obliqr, lambm0=lambm0, mvelpp=mvelpp, & - perpetual_run=perpetual_run, perpetual_ymd=perpetual_ymd, & - dtime=dtime, start_ymd=start_ymd, start_tod=start_tod, & - ref_ymd=ref_ymd, ref_tod=ref_tod, & - curr_ymd=curr_ymd, curr_tod=curr_tod, & - stop_ymd=stop_ymd, stop_tod=stop_tod, & - cam_out=cam_out, cam_in=cam_in) - - if (mediator_present) then - - if (single_column) then - - call cam_set_mesh_for_single_column(scol_lon, scol_lat, mesh, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - else - - ! generate the dof - lsize = columns_on_task - allocate(dof(lsize), stat=astat) - if (astat /= 0) then - write(tempc1, *) 'Allocate ERROR for dof, '//to_str(astat) - call shr_sys_abort(subname//trim(tempc1)) - end if - do n = 1, lsize - dof(n) = global_index_p(n) - end do - - ! create distGrid from global index array - DistGrid = ESMF_DistGridCreate(arbSeqIndexList=dof, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! read in the mesh - call NUOPC_CompAttributeGet(gcomp, name='mesh_atm', & - value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - mesh = ESMF_MeshCreate(filename=trim(cvalue), & - fileformat=ESMF_FILEFORMAT_ESMFMESH, & - elementDistgrid=Distgrid, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (masterproc) then - write(iulog,*)'mesh file for cam domain is ',trim(cvalue) - end if - - ! obtain mesh lats and lons - call ESMF_MeshGet(Emesh, spatialDim=spatialDim, & - numOwnedElements=numOwnedElements, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (numOwnedElements /= lsize) then - write(tempc1, '(i10)') numOwnedElements - write(tempc2, '(i10)') lsize - call ESMF_LogWrite(trim(subname)//": ERROR numOwnedElements "// & - trim(tempc1)//" not equal to local size "// & - trim(tempc2), ESMF_LOGMSG_INFO, rc=rc) - rc = ESMF_FAILURE - return - end if - allocate(ownedElemCoords(spatialDim*numOwnedElements), stat=astat) - if (astat /= 0) then - write(tempc1, *) 'Allocate ERROR for ownedElemCoords, ', & - to_str(astat) - call shr_sys_abort(subname//trim(tempc1)) - end if - allocate(lonMesh(lsize), stat=astat) - if (astat /= 0) then - write(tempc1, *) 'Allocate ERROR for lonMesh ', to_str(astat) - call shr_sys_abort(subname//trim(tempc1)) - end if - allocate(latMesh(lsize), stat=astat) - if (astat /= 0) then - write(tempc1, *) 'Allocate ERROR for latMesh ', to_str(astat) - call shr_sys_abort(subname//trim(tempc1)) - end if - call ESMF_MeshGet(Emesh, ownedElemCoords=ownedElemCoords) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - do n = 1,lsize - lonMesh(n) = ownedElemCoords(2*n-1) - ! Make sure we are 0 to 360 - if (lonMesh(n) < 0.0_r8) then - lonMesh(n) = lonMesh(n) + 180.0_r8 - end if - if (lonMesh(n) >= 360.0_r8) then - lonMesh(n) = lonMesh(n) - 360.0_r8 - end if - latMesh(n) = ownedElemCoords(2*n) - end do - - ! obtain internally generated cam lats and lons - allocate(lon(lsize), stat=astat) - if (astat /= 0) then - write(tempc1, *) 'Allocate ERROR for lon ', to_str(astat) - call shr_sys_abort(subname//trim(tempc1)) - end if - lon(:) = 0._r8 - allocate(lat(lsize), stat=astat) - if (astat /= 0) then - write(tempc1, *) 'Allocate ERROR for lat ', to_str(astat) - call shr_sys_abort(subname//trim(tempc1)) - end if - lat(:) = 0._r8 - n = 0 - ! latitudes and longitudes returned in radians - call get_rlat_all_p(lsize, lats) - call get_rlon_all_p(lsize, lons) - do n = 1, lsize - lat(n) = lats(n)*radtodeg - lon(n) = lons(n)*radtodeg - if (lon(n) >= 360.0_r8) then - lon(n) = lon(n) - 360.0_r8 - end if - end do - - ! Check diffs between internally generated lons and read values - do n = 1, lsize - if (abs(lonMesh(n) - lon(n)) > grid_tol) then - write(local_iulog, 100) n, lon(n), lonMesh(n), & - abs(lonMesh(n)-lon(n)) -100 format('ERROR: CAM n, lonmesh(n), lon(n), diff_lon = ',i6, & - 2(f21.13,3x),d21.5) - end if - if (abs(latMesh(n) - lat(n)) > grid_tol) then - write(local_iulog, 100) n, lat(n), latMesh(n), & - abs(latMesh(n)-lat(n)) -101 format('ERROR: CAM n, latmesh(n), lat(n), diff_lat = ',i6, & - 2(f21.13,3x),d21.5) - end if - end do - - ! deallocate memory - deallocate(ownedElemCoords) - deallocate(lon, lonMesh) - deallocate(lat, latMesh) - - end if ! if single_column - - ! realize the actively coupled fields - call realize_fields(gcomp, Emesh, flds_scalar_name, & - flds_scalar_num, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! Create cam export array and set the state scalars - call export_fields(gcomp, cam_out, rc=rc ) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call get_grid_dims(hdim1_d, hdim2_d) - call State_SetScalar(dble(hdim1_d), flds_scalar_index_nx, & - exportState, & - flds_scalar_name, flds_scalar_num, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call State_SetScalar(dble(hdim2_d), flds_scalar_index_ny, & - exportState, & - flds_scalar_name, flds_scalar_num, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! diagnostics - if (dbug_flag > 1) then - call State_diagnose(exportState,subname//':ES',rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - end if ! end of mediator_present if-block - - call shr_file_setLogUnit (shrlogunit) + !---------------------- + ! Obtain and load orbital values + !---------------------- + + call cam_orbital_init(gcomp, iulog, masterproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call cam_orbital_update(clock, iulog, masterproc, eccen, obliqr, lambm0, mvelpp, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call cam_ctrl_set_orbit(eccen, obliqr, lambm0, mvelpp) + + !---------------------- + ! Obtain attributes + !---------------------- + + call NUOPC_CompAttributeGet(gcomp, name='case_name', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) caseid + ctitle=caseid + + ! starting info + call NUOPC_CompAttributeGet(gcomp, name='start_type', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) start_type + call NUOPC_CompAttributeGet(gcomp, name='brnch_retain_casename', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) brnch_retain_casename + + ! single column input + call NUOPC_CompAttributeGet(gcomp, name='scol_lon', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) scol_lon + call NUOPC_CompAttributeGet(gcomp, name='scol_lat', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) scol_lat + call NUOPC_CompAttributeGet(gcomp, name='scol_spval', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) scol_spval + + ! For single column mode in cam need to have a valid single_column_lnd_domainfile for the mask + call NUOPC_CompAttributeGet(gcomp, name='single_column_lnd_domainfile', value=single_column_lnd_domainfile, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (scol_lon > scol_spval .and. scol_lat > scol_spval) then + if (trim(single_column_lnd_domainfile) /= 'UNSET') then + single_column = .true. + else + call shr_sys_abort('single_column_lnd_domainfile cannot be null for single column mode') + end if + else + single_column = .false. + end if + + ! aqua planet input + call NUOPC_CompAttributeGet(gcomp, name='aqua_planet', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) aqua_planet + + ! perpetual input + call NUOPC_CompAttributeGet(gcomp, name='perpetual', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) perpetual_run + call NUOPC_CompAttributeGet(gcomp, name='perpetual_ymd', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) perpetual_ymd + + ! TODO: query the config attributes for the number of instances - ASSUMES multi-driver + + ! TODO: must obtain model_doi_url from gcomp - for now hardwire to 'not_set' + model_doi_url = 'not_set' + + ! Initialize CAM, allocate cam_in and cam_out and determine + ! atm decomposition (needed to initialize gsmap) + ! for an initial run, cam_in and cam_out are allocated in cam_init + ! for a restart/branch run, cam_in and cam_out are allocated in restart + ! + !TODO: the following strings must not be hard-wired - must have module variables + ! like seq_infodata_start_type_type - maybe another entry in flds_mod? + + initial_run = .false. + restart_run = .false. + branch_run = .false. + if (trim(start_type) == trim('startup')) then + initial_run = .true. + else if (trim(start_type) == trim('continue') ) then + restart_run = .true. + else if (trim(start_type) == trim('branch')) then + branch_run = .true. + else + call shr_sys_abort( subname//' ERROR: unknown start_type' ) + end if + + ! DART always starts up as an initial run. + call NUOPC_CompAttributeGet(gcomp, name='data_assimilation_atm', value=cvalue, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue,*) dart_mode + end if + if (dart_mode) then + initial_run = .true. + restart_run = .false. + branch_run = .false. + end if + + ! Get properties from clock + call ESMF_ClockGet( clock, & + currTime=currTime, startTime=startTime, stopTime=stopTime, refTime=RefTime, & + timeStep=timeStep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet( currTime, yy=yy, mm=mm, dd=dd, s=curr_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yy,mm,dd,curr_ymd) + + call ESMF_TimeGet( startTime, yy=yy, mm=mm, dd=dd, s=start_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yy,mm,dd,start_ymd) + + call ESMF_TimeGet( stopTime, yy=yy, mm=mm, dd=dd, s=stop_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yy,mm,dd,stop_ymd) + + call ESMF_TimeGet( refTime, yy=yy, mm=mm, dd=dd, s=ref_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yy,mm,dd,ref_ymd) + + call ESMF_TimeIntervalGet( timeStep, s=dtime, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet( currTime, calkindflag=esmf_caltype, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (esmf_caltype == ESMF_CALKIND_NOLEAP) then + calendar = shr_cal_noleap + else if (esmf_caltype == ESMF_CALKIND_GREGORIAN) then + calendar = shr_cal_gregorian + else + call shr_sys_abort( subname//'ERROR:: bad calendar for ESMF' ) + end if + + ! Initialize module orbital values and update orbital + call cam_orbital_init(gcomp, iulog, masterproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call cam_orbital_update(clock, iulog, masterproc, eccen, obliqr, lambm0, mvelpp, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Initialize CAM + if (aqua_planet) then + perpetual_run = .true. + perpetual_ymd = aqua_perpetual_ymd + end if + + call cam_init( & + caseid=caseid, & + ctitle=ctitle, & + model_doi_url=model_doi_url, & + initial_run_in=initial_run, & + restart_run_in=restart_run, & + branch_run_in=branch_run, & + post_assim_in=dart_mode, & + calendar=calendar, & + brnch_retain_casename=brnch_retain_casename, & + aqua_planet=aqua_planet, & + single_column=single_column, & + scmlat=scol_lat, & + scmlon=scol_lon, & + eccen=eccen, & + obliqr=obliqr, & + lambm0=lambm0, & + mvelpp=mvelpp, & + perpetual_run=perpetual_run, & + perpetual_ymd=perpetual_ymd, & + dtime=dtime, & + start_ymd=start_ymd, & + start_tod=start_tod, & + ref_ymd=ref_ymd, & + ref_tod=ref_tod, & + stop_ymd=stop_ymd, & + stop_tod=stop_tod, & + curr_ymd=curr_ymd, & + curr_tod=curr_tod, & + cam_out=cam_out, & + cam_in=cam_in) + + if (mediator_present) then + + if (single_column) then + + call cam_set_mesh_for_single_column(scol_lon, scol_lat, model_mesh, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(dof(1), stat=ierr) + call check_allocate(ierr, subname, 'dof(1)', file=__FILE__, line=__LINE__) + dof(1) = 1 + + else + + ! generate the dof + allocate(dof(lsize), stat=ierr) + call check_allocate(ierr, subname, 'dof(lsize)', file=__FILE__, line=__LINE__) + do i = 1, lsize + dof(i) = global_index_p(i) + end do + + ! create distGrid from global index array + DistGrid = ESMF_DistGridCreate(arbSeqIndexList=dof, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! read in the mesh + call NUOPC_CompAttributeGet(gcomp, name='mesh_atm', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + model_mesh = ESMF_MeshCreate(filename=trim(cvalue), fileformat=ESMF_FILEFORMAT_ESMFMESH, & + elementDistgrid=Distgrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (masterproc) then + write(iulog,*)'mesh file for cam domain is ',trim(cvalue) + end if + + ! obtain mesh lats and lons + call ESMF_MeshGet(model_mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (numOwnedElements /= lsize) then + write(tempc1,'(i10)') numOwnedElements + write(tempc2,'(i10)') lsize + call ESMF_LogWrite(trim(subname)//": ERROR numOwnedElements "// trim(tempc1) // & + " not equal to local size "// trim(tempc2), ESMF_LOGMSG_INFO, rc=rc) + rc = ESMF_FAILURE + return + end if + allocate(ownedElemCoords(spatialDim*numOwnedElements), stat=ierr) + call check_allocate(ierr, subname, 'ownedElemCoords(spatialDim*numOwnedElements)', & + file=__FILE__, line=__LINE__) + call ESMF_MeshGet(model_mesh, ownedElemCoords=ownedElemCoords) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + do n = 1,lsize + lonMesh(n) = ownedElemCoords(2*n-1) + latMesh(n) = ownedElemCoords(2*n) + end do + + ! obtain internally generated cam lats and lons + lon(:) = 0._r8 + lat(:) = 0._r8 + ! latitudes and longitudes returned in radians + call get_rlat_all_p(lsize, lat) + call get_rlon_all_p(lsize, lon) + do i=1, lsize + lat(i) = lat(i)*radtodeg + lon(i) = lon(i)*radtodeg + end do + + ! error check differences between internally generated lons and those read in + do n = 1,lsize + if (abs(lonMesh(n) - lon(n)) > grid_tol .and. .not. & + abs(abs(lonMesh(n) - lon(n))- 360._r8) < grid_tol) then + write(6,100)n,lon(n),lonMesh(n), abs(lonMesh(n)-lon(n)) +100 format('ERROR: CAM n, lonmesh(n), lon(n), diff_lon = ',i6,2(f21.13,3x),d21.5) + call shr_sys_abort() + end if + if (abs(latMesh(n) - lat(n)) > grid_tol) then + write(6,100)n,lat(n),latMesh(n), abs(latMesh(n)-lat(n)) +101 format('ERROR: CAM n, latmesh(n), lat(n), diff_lat = ',i6,2(f21.13,3x),d21.5) + call shr_sys_abort() + end if + end do + + ! deallocate memory + deallocate(ownedElemCoords) + + end if ! end of if single_column + + ! realize the actively coupled fields + call realize_fields(gcomp, model_mesh, flds_scalar_name, flds_scalar_num, single_column, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Create model_clock as a module variable - needed for generating streams + model_clock = clock + + ! Create cam export array and set the state scalars + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call State_SetScalar(dble(hdim1_d), flds_scalar_index_nx, exportState, & + flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call State_SetScalar(dble(hdim2_d), flds_scalar_index_ny, exportState, & + flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! diagnostics + if (dbug_flag > 1) then + call State_diagnose(exportState,subname//':ES',rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + + end if ! end of mediator_present if-block + + call shr_log_setLogUnit (shrlogunit) #if (defined _MEMTRACE) - if(masterproc) then - write(iulog,*) TRIM(Sub), ':end::' - lbnum=1 - call memmon_dump_fort('memmon.out','atm_comp_nuopc_InitializeRealize:end::',lbnum) - call memmon_reset_addr() - end if + if(masterproc) then + write(iulog,*) TRIM(Sub) // ':end::' + lbnum=1 + call memmon_dump_fort('memmon.out','atm_comp_nuopc_InitializeRealize:end::',lbnum) + call memmon_reset_addr() + endif #endif - if (dbug_flag > 5) then - call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) - end if - - end subroutine InitializeRealize - - !========================================================================== - subroutine DataInitialize(gcomp, rc) - use string_utils, only: to_str - use cam_comp, only: cam_run1 - use cam_comp, only: cam_timestep_init - - ! Dummy arguments - type(ESMF_GridComp) :: gcomp - integer, intent(out) :: rc - - ! Local variables - type(ESMF_Clock) :: clock - type(ESMF_State) :: importState, exportState - type(ESMF_Time) :: currTime ! Current time - type(ESMF_TimeInterval) :: timeStep - type(ESMF_Field) :: field - character(len=ESMF_MAXSTR), allocatable :: fieldNameList(:) - character(len=ESMF_MAXSTR) :: fieldName - integer :: n, fieldCount - integer :: astat - integer :: shrlogunit ! original log unit - integer(ESMF_KIND_I8) :: stepno ! time step - integer :: dtime ! time step increment (sec) - integer :: atm_cpl_dt ! driver atm coupling time step - integer :: nstep ! CAM nstep - real(r8) :: nextsw_cday ! calendar of next atm shortwave - logical :: importDone ! true => import data is valid - logical :: atCorrectTime ! true => field is at correct time - character(len=CL) :: cvalue - character(len=*),parameter :: subname=trim(modName)//':(DataInitialize) ' - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - if (dbug_flag > 5) then - call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) - end if - - call shr_file_getLogUnit (shrlogunit) - call shr_file_setLogUnit (iulog) + if (dbug_flag > 5) then + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + end if + + end subroutine InitializeRealize + + !=============================================================================== + subroutine DataInitialize(gcomp, rc) + + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_Clock) :: clock + type(ESMF_State) :: importState, exportState + type(ESMF_Time) :: currTime ! Current time + type(ESMF_TimeInterval) :: timeStep + type(ESMF_Field) :: field + character(ESMF_MAXSTR),allocatable :: fieldNameList(:) + character(ESMF_MAXSTR) :: fieldName + integer :: n, fieldCount + integer :: shrlogunit ! original log unit + integer(ESMF_KIND_I8) :: stepno ! time step + integer :: atm_cpl_dt ! driver atm coupling time step + logical :: importDone ! true => import data is valid + logical :: atCorrectTime ! true => field is at correct time + character(CL) :: cvalue + character(len=*),parameter :: subname=trim(modName)//':(DataInitialize) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + if (dbug_flag > 5) then + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + end if + + call shr_log_getLogUnit (shrlogunit) + call shr_log_setLogUnit (iulog) #if (defined _MEMTRACE) - if (masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out','atm_comp_nuopc_DataInitialize:start::',lbnum) - end if + if (masterproc) then + lbnum=1 + call memmon_dump_fort('memmon.out','atm_comp_nuopc_DataInitialize:start::',lbnum) + endif #endif - !-------------------------------- - ! Query the Component for its clock, importState and exportState - !-------------------------------- - - call ESMF_GridCompGet(gcomp, clock=clock, importState=importState, & - exportState=exportState, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! get the current time out of the clock - call ESMF_ClockGet(clock, currTime=currTime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - if (dbug_flag > 1) then - call log_clock_advance(clock, 'CAM', iulog, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - !--------------------------------------------------------------- - if (mediator_present) then - !--------------------------------------------------------------- - - ! Determine if all the import state has been initialized - ! And if not initialized, then return - - call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - allocate(fieldNameList(fieldCount), stat=astat) - if (astat /= 0) then - write(fieldname, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(fieldname)) - end if - call ESMF_StateGet(importState, itemNameList=fieldNameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - importDone = .true. - do n=1, fieldCount - call ESMF_StateGet(importState, itemName=fieldNameList(n), & - field=field, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - atCorrectTime = NUOPC_IsAtTime(field, currTime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - if (.not. atCorrectTime) then - call ESMF_LogWrite(subname// & - "CAM - Initialize-Data-Dependency NOT YET SATISFIED!!!", & - ESMF_LOGMSG_INFO, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - importDone = .false. - exit ! break out of the loop when first not satisfied found - end if - end do - deallocate(fieldNameList) - - ! *** Import state has not been initialized - RETURN **** - if (.not. importDone) then - ! Simply return if the import has not been initialized - call ESMF_LogWrite(subname//"CAM - Initialize-Data-Dependency "// & - "Returning to mediator without doing tphysbc", & - ESMF_LOGMSG_INFO, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - RETURN - end if - - ! *** Import state has been initialized - continue with tphysbc *** - call ESMF_LogWrite(subname// & - "CAM - Initialize-Data-Dependency doing tphysbc", & - ESMF_LOGMSG_INFO, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! get the current step number and coupling interval - call ESMF_ClockGet(clock, TimeStep=timeStep, advanceCount=stepno, & - rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call ESMF_TimeIntervalGet(timeStep, s=atm_cpl_dt, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! For initial run, unpack the import state, run cam radiation/clouds - ! and return. - ! For restart run, read the import state from the restart and - ! run radiation/clouds and return - - ! Note - cam_run1 is called only for the purposes of finishing the - ! flux averaged calculation to compute cam-out - ! Note - cam_run1 is called on restart only to have cam internal - ! state consistent with the - ! cam_out state sent to the coupler - - if (stepno == 0) then - call import_fields(gcomp, cam_in, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call cam_read_srfrest(gcomp, clock, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call import_fields(gcomp, cam_in, restart_init=.true., rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - call cam_timestep_init () - call cam_run1 (cam_in, cam_out) - call export_fields(gcomp, cam_out, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - !CAMDEN TODO Remove once radiation has been fully implemented. -JN - ! Also note that this will need to be refactored to reflect the - ! recent CAM changes. + !-------------------------------- + ! Query the Component for its clock, importState and exportState + !-------------------------------- + + call ESMF_GridCompGet(gcomp, clock=clock, importState=importState, exportState=exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get the current time out of the clock + call ESMF_ClockGet(clock, currTime=currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (dbug_flag > 1) then + call log_clock_advance(clock, 'CAM', iulog, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + + !--------------------------------------------------------------- + if (mediator_present) then + !--------------------------------------------------------------- + + ! Determine if all the import state has been initialized + ! And if not initialized, then return + + call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + allocate(fieldNameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(importState, itemNameList=fieldNameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + importDone = .true. + do n=1, fieldCount + call ESMF_StateGet(importState, itemName=fieldNameList(n), field=field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + atCorrectTime = NUOPC_IsAtTime(field, currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (.not. atCorrectTime) then + call ESMF_LogWrite("CAM - Initialize-Data-Dependency NOT YET SATISFIED!!!", ESMF_LOGMSG_INFO, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + importDone = .false. + exit ! break out of the loop when first not satisfied found + end if + end do + deallocate(fieldNameList) + + ! *** Import state has not been initialized - RETURN **** + + if (.not. importDone) then + ! Simply return if the import has not been initialized + call ESMF_LogWrite("CAM - Initialize-Data-Dependency Returning to mediator without doing tphysbc", & + ESMF_LOGMSG_INFO, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + RETURN + end if + + ! *** Import state has been initialized - continue with tphysbc *** + + call ESMF_LogWrite("CAM - Initialize-Data-Dependency doing tphysbc", ESMF_LOGMSG_INFO, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get the current step number and coupling interval + call ESMF_ClockGet( clock, TimeStep=timeStep, advanceCount=stepno, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeIntervalGet( timeStep, s=atm_cpl_dt, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! For initial run, unpack the import state, run cam radiation/clouds and return + ! For restart run, read the import state from the restart and run radiation/clouds and return + + ! Note - cam_run1 is called only for the purposes of finishing the + ! flux averaged calculation to compute cam-out + ! Note - cam_run1 is called on restart only to have cam internal state consistent with the + ! cam_out state sent to the coupler + + if (stepno == 0) then + call import_fields( gcomp, cam_in, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call cam_timestep_init() + call cam_run1 ( cam_in, cam_out ) + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call cam_read_srfrest( gcomp, clock, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call import_fields( gcomp, cam_in, restart_init=.true., rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call cam_timestep_init() + call cam_run1 ( cam_in, cam_out ) + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + +!Remove once radiation (nextsw_cday) has been enabled in CAM-SIMA -JN. #if 0 - ! Compute time of next radiation computation, like in run method for exact restart - dtime = get_step_size() - nstep = get_nstep() - if (nstep < 1 .or. dtime < atm_cpl_dt) then - nextsw_cday = radiation_nextsw_cday() - else if (dtime == atm_cpl_dt) then - caldayp1 = get_curr_calday(offset=int(dtime)) - nextsw_cday = radiation_nextsw_cday() - if (caldayp1 /= nextsw_cday) nextsw_cday = -1._r8 - else - call shr_sys_abort('dtime must be less than or equal to atm_cpl_dt') - end if - - call State_SetScalar(nextsw_cday, flds_scalar_index_nextsw_cday, exportState, & - flds_scalar_name, flds_scalar_num, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return + ! Compute time of next radiation computation + call State_SetScalar(nextsw_cday, flds_scalar_index_nextsw_cday, exportState, & + flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return #endif - ! diagnostics - if (dbug_flag > 1) then - call State_diagnose(exportState,subname//':ES',rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if + ! diagnostics + if (dbug_flag > 1) then + call State_diagnose(exportState,subname//':ES',rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif - ! CAM data is now fully initialized + ! CAM data is now fully initialized - call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - allocate(fieldNameList(fieldCount), stat=astat) - if (astat /= 0) then - write(fieldname, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(fieldname)) - end if - call ESMF_StateGet(exportState, itemNameList=fieldNameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return + allocate(fieldNameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(exportState, itemNameList=fieldNameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - do n=1, fieldCount - call ESMF_StateGet(exportState, itemName=fieldNameList(n), & - field=field, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return + do n=1, fieldCount + call ESMF_StateGet(exportState, itemName=fieldNameList(n), field=field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - call NUOPC_SetAttribute(field, name="Updated", value="true", rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end do - deallocate(fieldNameList) + call NUOPC_SetAttribute(field, name="Updated", value="true", rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end do + deallocate(fieldNameList) - ! check whether all Fields in the exportState are "Updated" - if (NUOPC_IsUpdated(exportState)) then - call NUOPC_CompAttributeSet(gcomp, name="InitializeDataComplete", & - value="true", rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return + ! check whether all Fields in the exportState are "Updated" + if (NUOPC_IsUpdated(exportState)) then + call NUOPC_CompAttributeSet(gcomp, name="InitializeDataComplete", value="true", rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_LogWrite(subname// & - "CAM - Initialize-Data-Dependency SATISFIED!!!", & - ESMF_LOGMSG_INFO, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if + call ESMF_LogWrite("CAM - Initialize-Data-Dependency SATISFIED!!!", ESMF_LOGMSG_INFO, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if - !--------------------------------------------------------------- - else ! mediator is not present - !--------------------------------------------------------------- + !--------------------------------------------------------------- + else ! mediator is not present + !--------------------------------------------------------------- - call cam_timestep_init () - call cam_run1 (cam_in, cam_out) + call cam_timestep_init() + call cam_run1 ( cam_in, cam_out ) - call NUOPC_CompAttributeSet(gcomp, name="InitializeDataComplete", & - value="true", rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return + call NUOPC_CompAttributeSet(gcomp, name="InitializeDataComplete", value="true", rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - end if + end if - ! End redirection of share output to cam log - call shr_file_setLogUnit (shrlogunit) + ! End redirection of share output to cam log + call shr_log_setLogUnit (shrlogunit) #if (defined _MEMTRACE) - if(masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out','atm_comp_nuopc_DataInitialize:end::',lbnum) - end if + if(masterproc) then + lbnum=1 + call memmon_dump_fort('memmon.out','atm_comp_nuopc_DataInitialize:end::',lbnum) + endif #endif - if (dbug_flag > 5) then - call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) - end if - - end subroutine DataInitialize - - !=========================================================================== - subroutine ModelAdvance(gcomp, rc) - use cam_comp, only: cam_run1 - - use cam_comp, only: cam_run2, cam_run3, cam_run4 - use cam_comp, only: cam_timestep_init - use cam_comp, only: cam_timestep_final - - ! Run CAM - - ! Dummy arguments - type(ESMF_GridComp) :: gcomp - integer, intent(out) :: rc - - ! Local variables - type(ESMF_VM) :: vm - type(ESMF_Clock) :: clock - type(ESMF_Alarm) :: alarm - type(ESMF_Time) :: time - type(ESMF_Time) :: currTime ! Current time - type(ESMF_Time) :: nextTime ! Next timestep time - type(ESMF_TimeInterval) :: timeStep ! Clock, time-step - type(ESMF_State) :: importState - type(ESMF_State) :: exportState - character(CL) :: cvalue - integer :: shrlogunit ! original log unit - character(CL) :: case_name ! case name - real(r8) :: eccen - real(r8) :: obliqr - real(r8) :: lambm0 - real(r8) :: mvelpp - logical :: dosend ! true => send data back to driver - integer :: dtime ! time step increment (sec) - integer :: atm_cpl_dt ! driver atm coupling time step - integer :: ymd_sync ! Sync ymd - integer :: yr_sync ! Sync current year - integer :: mon_sync ! Sync current month - integer :: day_sync ! Sync current day - integer :: tod_sync ! Sync current time of day (sec) - integer :: ymd ! CAM current date (YYYYMMDD) - integer :: yr ! CAM current year - integer :: mon ! CAM current month - integer :: day ! CAM current day - integer :: tod ! CAM current time of day (sec) - real(r8) :: caldayp1 ! CAM calendar day for for next cam time step - real(r8) :: nextsw_cday ! calendar of next atm shortwave - logical :: rstwr ! .true. ==> write restart file before returning - logical :: nlend ! Flag signaling last time-step - integer :: lbnum - integer :: localPet, localPeCount - logical :: first_time = .true. - character(len=*),parameter :: subname=trim(modName)//':(ModelAdvance) ' - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - call ESMF_GridCompGet(gcomp, vm=vm, localPet=localPet, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMGet(vm, pet=localPet, peCount=localPeCount, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - - !$ call omp_set_num_threads(localPeCount) - - call shr_file_getLogUnit (shrlogunit) - call shr_file_setLogUnit (iulog) + if (dbug_flag > 5) then + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + end if + + end subroutine DataInitialize + + !=============================================================================== + subroutine ModelAdvance(gcomp, rc) + + use ESMF, only : ESMF_GridCompGet, esmf_vmget, esmf_vm + ! Run CAM + + ! Input/output variables + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_VM) :: vm + type(ESMF_Clock) :: clock + type(ESMF_Alarm) :: alarm + type(ESMF_Time) :: time + type(ESMF_Time) :: currTime ! Current time + type(ESMF_Time) :: nextTime ! Next timestep time + type(ESMF_TimeInterval) :: timeStep ! Clock, time-step + type(ESMF_State) :: importState + type(ESMF_State) :: exportState + character(CL) :: cvalue + integer :: shrlogunit ! original log unit + character(CL) :: case_name ! case name + real(r8) :: eccen + real(r8) :: obliqr + real(r8) :: lambm0 + real(r8) :: mvelpp + logical :: dosend ! true => send data back to driver + integer :: dtime ! time step increment (sec) + integer :: ymd_sync ! Sync ymd + integer :: yr_sync ! Sync current year + integer :: mon_sync ! Sync current month + integer :: day_sync ! Sync current day + integer :: tod_sync ! Sync current time of day (sec) + integer :: ymd ! CAM current date (YYYYMMDD) + integer :: yr ! CAM current year + integer :: mon ! CAM current month + integer :: day ! CAM current day + integer :: tod ! CAM current time of day (sec) + logical :: rstwr ! .true. ==> write restart file before returning + logical :: nlend ! Flag signaling last time-step + integer :: lbnum + integer :: localPet, localPeCount + logical :: first_time = .true. + character(len=*),parameter :: subname=trim(modName)//':(ModelAdvance) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + +!$ call omp_set_num_threads(nthrds) + + call shr_log_getLogUnit (shrlogunit) + call shr_log_setLogUnit (iulog) #if (defined _MEMTRACE) - if(masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out','atm_comp_nuopc_ModelAdvance:start::',lbnum) - end if + if(masterproc) then + lbnum=1 + call memmon_dump_fort('memmon.out','atm_comp_nuopc_ModelAdvance:start::',lbnum) + endif #endif - !-------------------------------- - ! Query the Component for its clock, importState and exportState - !-------------------------------- - - call NUOPC_ModelGet(gcomp, modelClock=clock, importState=importState, & - exportState=exportState, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - if (dbug_flag > 1) then - call log_clock_advance(clock, 'CAM', iulog, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - !-------------------------------- - ! Determine current time - !-------------------------------- - - call ESMF_ClockGet(clock, currTime=currTime) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_ClockGetNextTime(clock, nextTime=nextTime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call ESMF_TimeGet(nexttime, yy=yr_sync, mm=mon_sync, dd=day_sync, & - s=tod_sync, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - !---------------------- - ! Update and load orbital parameters - !---------------------- - - if (trim(orb_mode) == trim(orb_variable_year) .or. first_time) then - call cam_orbital_update(clock, iulog, masterproc, eccen, obliqr, & - lambm0, mvelpp, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call cam_ctrl_set_orbit(eccen, obliqr, lambm0, mvelpp) - end if - first_time = .false. - - !-------------------------------- - ! Run cam - !-------------------------------- - - ! Unpack import state - if (mediator_present) then - call t_startf ('CAM_import') - call State_GetScalar(importState, flds_scalar_index_nextsw_cday, & - nextsw_cday, flds_scalar_name, flds_scalar_num, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call State_diagnose(importState, string=subname//':IS', rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call import_fields(gcomp, cam_in, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call t_stopf ('CAM_import') - end if - - dosend = .false. - do while (.not. dosend) - - ! TODO: This is currently hard-wired - is there a better way for nuopc? - ! Need to not return when nstep = 0 and return when nstep = 1 - ! Note that the model clock is updated at the end of the time step - ! not at the beginning - if (get_nstep() > 0) then - dosend = .true. - end if - - ! Determine if time to write restart - call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', & - alarm=alarm, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - if (ChkErr(rc, __LINE__, u_FILE_u)) return - rstwr = .true. - call ESMF_AlarmRingerOff(alarm, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - rstwr = .false. - end if - - ! Determine if time to stop - call ESMF_ClockGetAlarm(clock, alarmname='alarm_stop', & - alarm=alarm, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - nlend = .true. - else - nlend = .false. - end if - - ! Run CAM (run2, run3, run4) - - call t_startf ('CAM_run2') - call cam_run2(cam_out, cam_in) - call t_stopf ('CAM_run2') - - call t_startf ('CAM_run3') - call cam_run3(cam_out) - call t_stopf ('CAM_run3') - - call t_startf ('CAM_run4') - call cam_run4(cam_out, cam_in, rstwr, nlend, yr_spec=yr_sync, & - mon_spec=mon_sync, day_spec=day_sync, sec_spec=tod_sync) - call t_stopf ('CAM_run4') - - call cam_timestep_final() - ! Advance cam time step - call t_startf ('CAM_adv_timestep') - call advance_timestep() - call t_stopf ('CAM_adv_timestep') - call cam_timestep_init() - - ! Run CAM4,5,6 radiation/clouds (run1 / tphysbc) - call t_startf ('CAM_run1') - call cam_run1 (cam_in, cam_out) - call t_stopf ('CAM_run1') - end do - - if (mediator_present) then - ! Set export fields - call t_startf ('CAM_export') - call export_fields(gcomp, cam_out, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call t_stopf ('CAM_export') - - ! Set the coupling scalars - ! Return time of next radiation calculation - albedos will need to be - ! calculated by each surface model at this time - - call ESMF_ClockGet(clock, TimeStep=timeStep, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call ESMF_TimeIntervalGet(timeStep, s=atm_cpl_dt, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - !CAMDEN TODO Remove once radiation has been fully implemented. -JN + !-------------------------------- + ! Query the Component for its clock, importState and exportState + !-------------------------------- + + call NUOPC_ModelGet(gcomp, modelClock=clock, importState=importState, exportState=exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (dbug_flag > 1) then + call log_clock_advance(clock, 'CAM', iulog, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + + !-------------------------------- + ! Determine current time + !-------------------------------- + + call ESMF_ClockGet( clock, currTime=currTime) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockGetNextTime(clock, nextTime=nextTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(nexttime, yy=yr_sync, mm=mon_sync, dd=day_sync, s=tod_sync, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Update and load orbital parameters + !---------------------- + + if (trim(orb_mode) == trim(orb_variable_year) .or. first_time) then + call cam_orbital_update(clock, iulog, masterproc, eccen, obliqr, lambm0, mvelpp, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call cam_ctrl_set_orbit(eccen, obliqr, lambm0, mvelpp) + end if + first_time = .false. + + !-------------------------------- + ! Run cam + !-------------------------------- + + ! Unpack import state + if (mediator_present) then + call t_startf ('CAM_import') + call State_diagnose(importState, string=subname//':IS', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call import_fields( gcomp, cam_in, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call t_stopf ('CAM_import') + end if + + dosend = .false. + do while (.not. dosend) + + ! TODO: This is currently hard-wired - is there a better way for nuopc? + ! Need to not return when nstep = 0 and return when nstep = 1 + ! Note that the model clock is updated at the end of the time step not at the beginning + if (get_nstep() > 0) then + dosend = .true. + end if + + ! Determine if time to write restart + + call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (ESMF_AlarmIsRinging(alarm, rc=rc)) then + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rstwr = .true. + call ESMF_AlarmRingerOff( alarm, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + rstwr = .false. + endif + + ! Determine if time to stop + + call ESMF_ClockGetAlarm(clock, alarmname='alarm_stop', alarm=alarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (ESMF_AlarmIsRinging(alarm, rc=rc)) then + nlend = .true. + else + nlend = .false. + endif + + ! Run CAM (run2, run3, run4) + + call t_startf ('CAM_run2') + call cam_run2( cam_out, cam_in ) + call t_stopf ('CAM_run2') + + call t_startf ('CAM_run3') + call cam_run3( cam_out ) + call t_stopf ('CAM_run3') + + call t_startf ('CAM_run4') + call cam_run4( cam_out, cam_in, rstwr, nlend, & + yr_spec=yr_sync, mon_spec=mon_sync, day_spec=day_sync, sec_spec=tod_sync) + call t_stopf ('CAM_run4') + call cam_timestep_final() + + ! Advance cam time step + + call t_startf ('CAM_adv_timestep') + call advance_timestep() + call t_stopf ('CAM_adv_timestep') + call cam_timestep_init() + + ! Run cam radiation/clouds (run1) + + call t_startf ('CAM_run1') + call cam_run1 ( cam_in, cam_out ) + call t_stopf ('CAM_run1') + + end do + + if (mediator_present) then + ! Set export fields + call t_startf ('CAM_export') + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call t_stopf ('CAM_export') + + ! Set the coupling scalars +!Remove once radiation (nextsw_cday) has been enabled in CAM-SIMA -JN. #if 0 - dtime = get_step_size() - if (dtime < atm_cpl_dt) then - nextsw_cday = radiation_nextsw_cday() - else if (dtime == atm_cpl_dt) then - caldayp1 = get_curr_calday(offset=int(dtime)) - nextsw_cday = radiation_nextsw_cday() - if (caldayp1 /= nextsw_cday) nextsw_cday = -1._r8 - else - call shr_sys_abort('dtime must be less than or equal to atm_cpl_dt') - end if - - call State_SetScalar(nextsw_cday, flds_scalar_index_nextsw_cday, & - exportState, flds_scalar_name, flds_scalar_num, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return + ! Return time of next radiation calculation - albedos will need to be + ! calculated by each surface model at this time + call State_SetScalar(nextsw_cday, flds_scalar_index_nextsw_cday, exportState, & + flds_scalar_name, flds_scalar_num, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return #endif - ! diagnostics - if (dbug_flag > 1) then - call State_diagnose(exportState, string=subname//':ES',rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (masterproc) then - call log_clock_advance(clock, 'CAM', iulog, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - end if - - ! Write merged surface data restart file if appropriate - if (rstwr) then - call cam_write_srfrest(gcomp, yr_spec=yr_sync, & - mon_spec=mon_sync, day_spec=day_sync, sec_spec=tod_sync, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - else - - ! if there is no mediator, then write the clock info to a driver restart file - if (rstwr) then - call cam_write_clockrest(clock, yr_sync, mon_sync, day_sync, & - tod_sync, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - end if - - ! Check for consistency of internal cam clock with master sync clock - ! Note that the driver clock has not been updated yet - so at this point - ! CAM is actually 2 coupling intervals (or physics time steps) ahead - ! of the driver clock - dtime = get_step_size() - call get_curr_date(yr, mon, day, tod, offset=-2*dtime) - ymd = yr*10000 + mon*100 + day - tod = tod - - call ESMF_ClockGet(clock, currTime=currTime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call ESMF_TimeGet(currTime, yy=yr_sync, mm=mon_sync, dd=day_sync, & - s=tod_sync, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call shr_cal_ymd2date(yr_sync, mon_sync, day_sync, ymd_sync) - - if ((ymd /= ymd_sync) .and. (tod /= tod_sync))then - write(iulog,*)' cam ymd=',ymd, ' cam tod= ',tod - write(iulog,*)'sync ymd=',ymd_sync,' sync tod= ',tod_sync - call shr_sys_abort(subname// & - ': CAM clock is not in sync with master Sync Clock') - end if + ! diagnostics + if (dbug_flag > 1) then + call State_diagnose(exportState, string=subname//':ES',rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (masterproc) then + call log_clock_advance(clock, 'CAM', iulog, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + endif + + ! Write merged surface data restart file if appropriate + if (rstwr) then + call cam_write_srfrest( gcomp, & + yr_spec=yr_sync, mon_spec=mon_sync, day_spec=day_sync, sec_spec=tod_sync, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + else + + ! if there is no mediator, then write the clock info to a driver restart file + if (rstwr) then + call cam_write_clockrest( clock, yr_sync, mon_sync, day_sync, tod_sync, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end if + + ! Check for consistency of internal cam clock with master sync clock + ! Note that the driver clock has not been updated yet - so at this point + ! CAM is actually 2 coupling intervals (or physics time steps) ahead of the driver clock + dtime = get_step_size() + call get_curr_date( yr, mon, day, tod, offset=-2*dtime ) + ymd = yr*10000 + mon*100 + day + tod = tod + + call ESMF_ClockGet( clock, currTime=currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet( currTime, yy=yr_sync, mm=mon_sync, dd=day_sync, s=tod_sync, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yr_sync, mon_sync, day_sync, ymd_sync) + + if ( (ymd /= ymd_sync) .and. (tod /= tod_sync) )then + write(iulog,*)' cam ymd=',ymd ,' cam tod= ',tod + write(iulog,*)'sync ymd=',ymd_sync,' sync tod= ',tod_sync + call shr_sys_abort( subname//': CAM clock is not in sync with master Sync Clock' ) + end if #if (defined _MEMTRACE) - if(masterproc) then - lbnum=1 - call memmon_dump_fort('memmon.out','atm_comp_nuopc_ModelAdvance:end::',lbnum) - end if + if(masterproc) then + lbnum=1 + call memmon_dump_fort('memmon.out','atm_comp_nuopc_ModelAdvance:end::',lbnum) + endif #endif - !-------------------------------- - ! Reset shr logging to my original values - !-------------------------------- - - call shr_file_setLogUnit (shrlogunit) - - end subroutine ModelAdvance - - !========================================================================== - - subroutine ModelSetRunClock(gcomp, rc) - - ! Dummy arguments - type(ESMF_GridComp) :: gcomp - integer, intent(out) :: rc - - ! Local variables - type(ESMF_Clock) :: mclock, dclock - type(ESMF_Time) :: mcurrtime, dcurrtime - type(ESMF_Time) :: mstoptime - type(ESMF_TimeInterval) :: mtimestep, dtimestep - character(len=256) :: cvalue - character(len=256) :: restart_option ! Restart option units - integer :: restart_n ! Number until restart interval - integer :: restart_ymd ! Restart date (YYYYMMDD) - type(ESMF_ALARM) :: restart_alarm - character(len=256) :: stop_option ! Stop option units - integer :: stop_n ! Number until stop interval - integer :: stop_ymd ! Stop date (YYYYMMDD) - type(ESMF_ALARM) :: stop_alarm - character(len=128) :: name - integer :: alarmcount - character(len=*),parameter :: subname=trim(modName)//':(ModelSetRunClock) ' - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! query the Component for its clocks - call NUOPC_ModelGet(gcomp, driverClock=dclock, modelClock=mclock, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_ClockGet(dclock, currTime=dcurrtime, timeStep=dtimestep, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_ClockGet(mclock, currTime=mcurrtime, timeStep=mtimestep, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - !----------------------------------------------------------------------- - ! force model clock currtime and timestep to match driver and set stoptime - !----------------------------------------------------------------------- - - mstoptime = mcurrtime + dtimestep - call ESMF_ClockSet(mclock, currTime=dcurrtime, timeStep=dtimestep, & - stopTime=mstoptime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - !-------------------------------- - ! set restart and stop alarms - !-------------------------------- - - call ESMF_ClockGetAlarmList(mclock, alarmlistflag=ESMF_ALARMLIST_ALL, & - alarmCount=alarmCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - if (alarmCount == 0) then - - call ESMF_GridCompGet(gcomp, name=name, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call ESMF_LogWrite(subname//'setting alarms for'//trim(name), & - ESMF_LOGMSG_INFO) - - !---------------- - ! Restart alarm - !---------------- - call NUOPC_CompAttributeGet(gcomp, name="restart_option", & - value=restart_option, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call NUOPC_CompAttributeGet(gcomp, name="restart_n", value=cvalue, & - rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) restart_n - - call NUOPC_CompAttributeGet(gcomp, name="restart_ymd", value=cvalue, & - rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) restart_ymd - - call alarmInit(mclock, restart_alarm, restart_option, & - opt_n = restart_n, & - opt_ymd = restart_ymd, & - RefTime = mcurrTime, & - alarmname = 'alarm_restart', rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_AlarmSet(restart_alarm, clock=mclock, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - !---------------- - ! Stop alarm - !---------------- - call NUOPC_CompAttributeGet(gcomp, name="stop_option", & - value=stop_option, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call NUOPC_CompAttributeGet(gcomp, name="stop_n", value=cvalue, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) stop_n - - call NUOPC_CompAttributeGet(gcomp, name="stop_ymd", value=cvalue, & - rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - read(cvalue,*) stop_ymd - - call alarmInit(mclock, stop_alarm, stop_option, & - opt_n = stop_n, & - opt_ymd = stop_ymd, & - RefTime = mcurrTime, & - alarmname = 'alarm_stop', rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_AlarmSet(stop_alarm, clock=mclock, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - end if - - !----------------------------------------------------------------------- - ! Advance model clock to trigger alarms then reset model clock - ! back to currtime - !----------------------------------------------------------------------- - - call ESMF_ClockAdvance(mclock,rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_ClockSet(mclock, currTime=dcurrtime, timeStep=dtimestep, & - stopTime=mstoptime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - end subroutine ModelSetRunClock - - !========================================================================== - subroutine ModelFinalize(gcomp, rc) - use cam_comp, only: cam_final - use cam_comp, only: cam_timestep_final - - ! Dummy arguments - type(ESMF_GridComp) :: gcomp - integer, intent(out) :: rc - - ! Local variables - integer :: shrlogunit ! original log unit - real(r8) :: nextsw_cday ! calendar of next atm shortwave - type(ESMF_State) :: importState - character(len=*), parameter :: F00 = "('(atm_comp_nuopc) ',8a)" - character(len=*), parameter :: F91 = "('(atm_comp_nuopc) ',73('-'))" - character(len=*), parameter :: subname=trim(modName)//':(ModelFinalize) ' - !------------------------------------------------------------------------ - - !-------------------------------- - ! Finalize routine - !-------------------------------- - - rc = ESMF_SUCCESS - - call shr_file_getLogUnit (shrlogunit) - call shr_file_setLogUnit (iulog) - - !!XXgoldyXX: Is this needed? - ! Unpack import state - if (mediator_present) then - call t_startf('CAM_import') - call State_GetScalar(importState, flds_scalar_index_nextsw_cday, & - nextsw_cday, flds_scalar_name, flds_scalar_num, rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call State_diagnose(importState, string=subname//':IS', rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) then - return - end if - - call import_fields(gcomp, cam_in, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) then - return - end if - call t_stopf('CAM_import') - end if - - call cam_timestep_final() - call cam_final(cam_out, cam_in) - - !CAMDEN TODO: export output state? Needed for finalize? - - if (masterproc) then - write(iulog,F91) - write(iulog,F00) 'CAM: end of main integration loop' - write(iulog,F91) - end if - - call shr_file_setLogUnit(shrlogunit) - - end subroutine ModelFinalize - - !========================================================================== - subroutine cam_orbital_init(gcomp, logunit, mastertask, rc) - - !---------------------------------------------------------- - ! Initialize orbital related values - !---------------------------------------------------------- - - ! Dummy arguments - type(ESMF_GridComp), intent(in) :: gcomp - integer, intent(in) :: logunit - logical, intent(in) :: mastertask - integer, intent(out) :: rc ! output error - - ! Local variables - character(len=CL) :: msgstr ! temporary - character(len=CL) :: cvalue ! temporary - character(len=*), parameter :: subname = "(cam_orbital_init)" - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! Determine orbital attributes from input - call NUOPC_CompAttributeGet(gcomp, name="orb_mode", value=cvalue, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) orb_mode - - call NUOPC_CompAttributeGet(gcomp, name="orb_iyear", value=cvalue, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) orb_iyear - - call NUOPC_CompAttributeGet(gcomp, name="orb_iyear_align", & - value=cvalue, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) orb_iyear_align - - call NUOPC_CompAttributeGet(gcomp, name="orb_obliq", value=cvalue, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) orb_obliq - - call NUOPC_CompAttributeGet(gcomp, name="orb_eccen", value=cvalue, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) orb_eccen - - call NUOPC_CompAttributeGet(gcomp, name="orb_mvelp", value=cvalue, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) orb_mvelp - - ! Error checks - if (trim(orb_mode) == trim(orb_fixed_year)) then - orb_obliq = SHR_ORB_UNDEF_REAL - orb_eccen = SHR_ORB_UNDEF_REAL - orb_mvelp = SHR_ORB_UNDEF_REAL - if (orb_iyear == SHR_ORB_UNDEF_INT) then - if (mastertask) then - write(logunit,*) trim(subname), & - ' ERROR: invalid settings orb_mode =',trim(orb_mode) - write(logunit,*) trim(subname), & - ' ERROR: fixed_year settings = ',orb_iyear - write(msgstr, *) ' ERROR: invalid settings for orb_mode ', & - trim(orb_mode) - end if - call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, & - line=__LINE__, file=__FILE__, rcToReturn=rc) - return ! bail out - end if - else if (trim(orb_mode) == trim(orb_variable_year)) then - orb_obliq = SHR_ORB_UNDEF_REAL - orb_eccen = SHR_ORB_UNDEF_REAL - orb_mvelp = SHR_ORB_UNDEF_REAL - if ( (orb_iyear == SHR_ORB_UNDEF_INT) .or. & - (orb_iyear_align == SHR_ORB_UNDEF_INT)) then - if (mastertask) then - write(logunit,*) trim(subname), & - ' ERROR: invalid settings orb_mode =',trim(orb_mode) - write(logunit,*) trim(subname), & - ' ERROR: variable_year settings = ', orb_iyear, & - orb_iyear_align - write(msgstr, *) subname, & - ' ERROR: invalid settings for orb_mode ', trim(orb_mode) - end if - call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, & - line=__LINE__, file=__FILE__, rcToReturn=rc) - return ! bail out - end if - else if (trim(orb_mode) == trim(orb_fixed_parameters)) then - !-- force orb_iyear to undef to make sure shr_orb_params works properly - orb_iyear = SHR_ORB_UNDEF_INT - orb_iyear_align = SHR_ORB_UNDEF_INT - if (orb_eccen == SHR_ORB_UNDEF_REAL .or. & - orb_obliq == SHR_ORB_UNDEF_REAL .or. & - orb_mvelp == SHR_ORB_UNDEF_REAL) then - if (mastertask) then - write(logunit,*) trim(subname),' ERROR: invalid settings orb_mode =',trim(orb_mode) - write(logunit,*) trim(subname), ' ERROR: orb_eccen = ', orb_eccen - write(logunit,*) trim(subname), ' ERROR: orb_obliq = ', orb_obliq - write(logunit,*) trim(subname), ' ERROR: orb_mvelp = ', orb_mvelp - write(msgstr, *) subname, & - ' ERROR: invalid settings for orb_mode ', trim(orb_mode) - end if - call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, & - line=__LINE__, file=__FILE__, rcToReturn=rc) - return ! bail out - end if - else - write(msgstr, *) subname, ' ERROR: invalid orb_mode ', trim(orb_mode) - call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, & - line=__LINE__, file=__FILE__, rcToReturn=rc) - rc = ESMF_FAILURE - return ! bail out - end if - - end subroutine cam_orbital_init - - !========================================================================== - subroutine cam_orbital_update(clock, logunit, mastertask, eccen, & - obliqr, lambm0, mvelpp, rc) - - !---------------------------------------------------------- - ! Update orbital settings - !---------------------------------------------------------- - - ! Dummy arguments - type(ESMF_Clock), intent(in) :: clock - integer, intent(in) :: logunit - logical, intent(in) :: mastertask - real(R8), intent(inout) :: eccen ! orbital eccentricity - real(R8), intent(inout) :: obliqr ! Earths obliquity in rad - ! lambm0: The mean longitude of perihelion at vernal equinox (radians) - real(R8), intent(inout) :: lambm0 - ! mvelpp: Moving vernal equinox longitude of perihelion plus pi (radians) - real(R8), intent(inout) :: mvelpp - integer, intent(out) :: rc ! output error - - ! Local variables - type(ESMF_Time) :: CurrTime ! current time - integer :: year ! model year at current time - integer :: orb_year ! orbital year for current orbital computation - character(len=CL) :: msgstr ! temporary - character(len=*), parameter :: subname = "(cam_orbital_update)" - !------------------------------------------- - - rc = ESMF_SUCCESS - - if (trim(orb_mode) == trim(orb_variable_year)) then - call ESMF_ClockGet(clock, CurrTime=CurrTime, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_TimeGet(CurrTime, yy=year, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - orb_year = orb_iyear + (year - orb_iyear_align) - else - orb_year = orb_iyear - end if - - eccen = orb_eccen - call shr_orb_params(orb_year, eccen, orb_obliq, orb_mvelp, obliqr, & - lambm0, mvelpp, mastertask) - - if ( (eccen == SHR_ORB_UNDEF_REAL) .or. & - (obliqr == SHR_ORB_UNDEF_REAL) .or. & - (mvelpp == SHR_ORB_UNDEF_REAL) .or. & - (lambm0 == SHR_ORB_UNDEF_REAL)) then - write(msgstr, *) subname, ' ERROR: orb params incorrect' - call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, & - line=__LINE__, file=__FILE__, rcToReturn=rc) - return ! bail out - end if - - end subroutine cam_orbital_update - - !========================================================================== - subroutine cam_read_srfrest(gcomp, clock, rc) - use string_utils, only: to_str - use ioFileMod, only: cam_get_file - - ! Dummy arguments - type(ESMF_GridComp) :: gcomp - type(ESMF_Clock), intent(inout) :: clock - integer, intent(out) :: rc - - ! Local variables - type(ESMF_State) :: importState, exportState - type(ESMF_Field) :: lfield - integer :: lrank - integer :: rcode ! return error code - integer :: nf,n - type(file_desc_t) :: file - type(io_desc_t), pointer :: iodesc - integer :: fieldCount - integer :: astat - character(ESMF_MAXSTR),allocatable :: fieldNameList(:) - type(var_desc_t) :: varid - real(r8), pointer :: fldptr(:) - real(r8), pointer :: tmpptr(:) - real(r8), pointer :: fldptr2d(:,:) - type(ESMF_Time) :: currTime ! time at previous interval - integer :: yr_spec ! Current year - integer :: mon_spec ! Current month - integer :: day_spec ! Current day - integer :: sec_spec ! Current time of day (sec) - character(len=CL) :: fname_srf_cam ! surface restart filename - character(len=CL) :: pname_srf_cam ! surface restart full pathname - character(len=PIO_MAX_NAME) :: varname - integer :: ungriddedUBound(1) ! currently the size must equal 1 for rank 2 fieldds - integer :: gridToFieldMap(1) ! currently the size must equal 1 for rank 2 fieldds - integer :: lsize - integer :: err_handling - character(len=8) :: cvalue - integer :: nloop - character(len=4) :: prefix - character(len=*), parameter :: subname = "(cam_read_srfrest) " - - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! ------------------------------ - ! Get surface restart dataset - ! ------------------------------ - - call ESMF_GridCompGet(gcomp, clock=clock, importState=importState, & - exportState=exportState, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_ClockGet(clock, currTime=currTime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_TimeGet(currTime, yy=yr_spec, mm=mon_spec, dd=day_spec, & - s=sec_spec, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - fname_srf_cam = interpret_filename_spec(rsfilename_spec_cam, & - case=cam_initfiles_get_caseid(), yr_spec=yr_spec, & - mon_spec=mon_spec, day_spec=day_spec, sec_spec= sec_spec) - pname_srf_cam = trim(cam_initfiles_get_restdir())//fname_srf_cam - call cam_get_file(pname_srf_cam, fname_srf_cam) - - ! ------------------------------ - ! Open restart file - ! ------------------------------ - call cam_pio_openfile(File, fname_srf_cam, 0) - call cam_pio_newdecomp(iodesc, (/num_global_phys_cols/), dof, pio_double) - call pio_seterrorhandling(File, pio_bcast_error, oldmethod=err_handling) - - ! ------------------------------ - ! Read in import and export fields - ! ------------------------------ - do nloop = 1, 2 - if (nloop == 1) then - prefix = 'x2a_' ! import fields - call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - allocate(fieldnameList(fieldCount), stat=astat) - if (astat /= 0) then - write(varname, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(varname)) - end if - call ESMF_StateGet(importState, itemNameList=fieldnameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - prefix = 'a2x_' ! export fields - call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - allocate(fieldnameList(fieldCount), stat=astat) - if (astat /= 0) then - write(varname, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(varname)) - end if - call ESMF_StateGet(exportState, itemNameList=fieldnameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - ! Loop over fields in import or export state - do nf = 1, fieldCount - - if (trim(fieldnameList(nf)) == flds_scalar_name) CYCLE - - ! Determine dimension of field - if (nloop == 1) then - call ESMF_StateGet(importState, & - itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call ESMF_StateGet(exportState, & - itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - call ESMF_FieldGet(lfield, rank=lrank, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - - if (lrank == 1) then - - call ESMF_FieldGet(lfield, farrayPtr=fldptr, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - varname = trim(prefix)//trim(fieldnameList(nf)) - rcode = pio_inq_varid(File,trim(varname), varid) - if (rcode == pio_noerr) then - call pio_read_darray(File, varid, iodesc, fldptr, rcode) - else - if (masterproc) then - write(iulog,*) 'cam_read_srfrest warning: field ', & - trim(varname),' is not on restart file' - write(iulog,*) & - ' for backwards compatibility will set it to 0' - end if - fldptr(:) = 0._r8 - end if - - else if (lrank == 2) then - - ! There is an output variable for each element of the - ! undistributed dimension - call ESMF_FieldGet(lfield, ungriddedUBound=ungriddedUBound, & - gridToFieldMap=gridToFieldMap, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_FieldGet(lfield, farrayPtr=fldptr2d, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - if (gridToFieldMap(1) == 1) then - lsize = size(fldptr2d, dim=1) - else if (gridToFieldMap(1) == 2) then - lsize = size(fldptr2d, dim=2) - end if - - allocate(tmpptr(lsize), stat=astat) - if (astat /= 0) then - write(varname, *) 'Allocate ERROR for tmpptr ', to_str(astat) - call shr_sys_abort(subname//trim(varname)) - end if - do n = 1, ungriddedUBound(1) - write(cvalue,'(i0)') n - varname = trim(prefix)//trim(fieldnameList(nf))//trim(cvalue) - rcode = pio_inq_varid(File,trim(varname), varid) - - if (rcode == pio_noerr) then - call pio_read_darray(File, varid, iodesc, tmpptr, rcode) - else - if (masterproc) then - write(iulog,*) 'cam_read_srfrest warning: field ', & - trim(varname),' is not on restart file' - write(iulog,*) & - 'for backwards compatibility will set it to 0' - end if - tmpptr(:) = 0._r8 - end if - if (gridToFieldMap(1) == 1) then - fldptr2d(:,n) = tmpptr(:) - else if (gridToFieldMap(1) == 2) then - fldptr2d(n,:) = tmpptr(:) - end if - end do - deallocate(tmpptr) - - end if ! end lrank if block - end do - deallocate(fieldnameList) - end do - - ! ------------------------------ - ! Close file - ! ------------------------------ - call pio_seterrorhandling(File, err_handling) - call pio_freedecomp(File, iodesc) - call cam_pio_closefile(File) - - end subroutine cam_read_srfrest - - !========================================================================= - subroutine cam_write_srfrest(gcomp, yr_spec, mon_spec, day_spec, & - sec_spec, rc) - use string_utils, only: to_str - - ! Dummy Arguments - type(ESMF_GridComp) :: gcomp - integer, intent(in) :: yr_spec ! Simulation year - integer, intent(in) :: mon_spec ! Simulation month - integer, intent(in) :: day_spec ! Simulation day - integer, intent(in) :: sec_spec ! Seconds into current simulation day - integer, intent(out) :: rc ! error code - - ! Local variables - type(ESMF_State) :: importState, exportState - type(ESMF_Field) :: lField - integer :: lrank - integer :: rcode ! return error code - integer :: dimid(1), nf, n - type(file_desc_t) :: file - type(io_desc_t), pointer :: iodesc - integer :: astat - integer :: fieldCount - character(ESMF_MAXSTR), allocatable :: fieldnameList(:) - type(var_desc_t) :: varid - real(r8), pointer :: fldptr1d(:) - real(r8), pointer :: fldptr2d(:,:) - character(len=PIO_MAX_NAME) :: varname - character(len=CL) :: fname_srf_cam ! surface restart filename - character(len=8) :: cvalue - integer :: nloop - character(len=4) :: prefix - integer :: ungriddedUBound(1) ! currently the size must equal 1 for rank 2 fieldds - integer :: gridToFieldMap(1) ! currently the size must equal 1 for rank 2 fieldds - character(len=*), parameter :: subname = "(cam_write_srfrest) " - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! ---------------------- - ! Get import and export states - ! ---------------------- - - call ESMF_GridCompGet(gcomp, importState=importState, & - exportState=exportState, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! ---------------------- - ! Open surface restart dataset - ! ---------------------- - - fname_srf_cam = interpret_filename_spec(rsfilename_spec_cam, & - yr_spec=yr_spec, mon_spec=mon_spec, day_spec=day_spec, & - sec_spec=sec_spec) - - call cam_pio_createfile(File, fname_srf_cam, 0) - call cam_pio_newdecomp(iodesc, (/num_global_phys_cols/), dof, pio_double) - - ! ---------------------- - ! Define dimensions - ! ---------------------- - - rcode = pio_def_dim(File, 'x2a_nx', num_global_phys_cols, dimid(1)) - rcode = pio_def_dim(File, 'a2x_nx', num_global_phys_cols, dimid(1)) - - ! ---------------------- - ! Define import and export variable ids - ! ---------------------- - - do nloop = 1, 2 - - if (nloop == 1) then - prefix = 'x2a_' ! import fields - call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - allocate(fieldNameList(fieldCount), stat=astat) - if (astat /= 0) then - write(fname_srf_cam, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(fname_srf_cam)) - end if - call ESMF_StateGet(importState, itemNameList=fieldNameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - prefix = 'a2x_' ! export fields - call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - allocate(fieldNameList(fieldCount), stat=astat) - if (astat /= 0) then - write(fname_srf_cam, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(fname_srf_cam)) - end if - call ESMF_StateGet(exportState, itemNameList=fieldNameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - do nf = 1,fieldCount - - if (trim(fieldNameList(nf)) == flds_scalar_name) CYCLE - - if (nloop == 1) then - call ESMF_StateGet(importState, & - itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call ESMF_StateGet(exportState, & - itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - call ESMF_FieldGet(lfield, rank=lrank, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - - if (lrank == 1) then - - varname = trim(prefix)//trim(fieldNameList(nf)) - rcode = pio_def_var(File,trim(varname), PIO_DOUBLE, dimid, varid) - rcode = pio_put_att(File, varid, "_fillvalue", fillvalue) - - else if (lrank == 2) then - - ! Determine the size of the ungridded dimension and the - ! index where the undistributed dimension is located - call ESMF_FieldGet(lfield, ungriddedUBound=ungriddedUBound, & - gridToFieldMap=gridToFieldMap, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - - ! Output for each ungriddedUbound index - do n = 1,ungriddedUBound(1) - write(cvalue,'(i0)') n - varname = trim(prefix)//trim(fieldNameList(nf))//trim(cvalue) - rcode = pio_def_var(File,trim(varname), PIO_DOUBLE, & - dimid, varid) - rcode = pio_put_att(File, varid, "_fillvalue", fillvalue) - end do - - end if ! end if-block over rank size - - end do ! end loop over import or export fieldsfields - deallocate(fieldNameList) - end do - - ! ---------------------- - ! End definition phase - ! ---------------------- - - rcode = pio_enddef(File)! don't check return code, might be enddef already - - ! ---------------------- - ! Write the restart data for the import fields and export fields - ! ---------------------- - - do nloop = 1, 2 - - if (nloop == 1) then - prefix = 'x2a_' ! import fields - call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - allocate(fieldNameList(fieldCount), stat=astat) - if (astat /= 0) then - write(fname_srf_cam, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(fname_srf_cam)) - end if - call ESMF_StateGet(importState, itemNameList=fieldNameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - prefix = 'a2x_' ! export fields - call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - allocate(fieldNameList(fieldCount), stat=astat) - if (astat /= 0) then - write(fname_srf_cam, *) 'Allocate ERROR for fieldNameList ', & - to_str(astat) - call shr_sys_abort(subname//trim(fname_srf_cam)) - end if - call ESMF_StateGet(exportState, itemNameList=fieldNameList, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - - do nf = 1,fieldCount - - if (trim(fieldNameList(nf)) == flds_scalar_name) CYCLE - - if (nloop == 1) then - call ESMF_StateGet(importState, & - itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - else - call ESMF_StateGet(exportState, & - itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - end if - call ESMF_FieldGet(lfield, rank=lrank, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - - if (lrank == 1) then - - varname = trim(prefix)//trim(fieldNameList(nf)) - rcode = pio_inq_varid(File, trim(varname), varid) - call ESMF_FieldGet(lfield, farrayPtr=fldptr1d, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call pio_write_darray(File, varid, iodesc, fldptr1d, rcode) - - else if (lrank == 2) then - - ! There is an output variable for each element of the - ! undistributed dimension - call ESMF_FieldGet(lfield, ungriddedUBound=ungriddedUBound, & - rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_FieldGet(lfield, farrayPtr=fldptr2d, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - do n = 1,ungriddedUBound(1) - write(cvalue,'(i0)') n - varname = trim(prefix)//trim(fieldNameList(nf))//trim(cvalue) - rcode = pio_inq_varid(File, trim(varname), varid) - if (gridToFieldMap(1) == 1) then - call pio_write_darray(File, varid, iodesc, & - fldptr2d(:,n), rcode, fillval=fillvalue) - else if (gridToFieldMap(1) == 2) then - call pio_write_darray(File, varid, iodesc, & - fldptr2d(n,:), rcode, fillval=fillvalue) - end if - end do - - end if - end do ! end loop over import or export fields - deallocate(fieldNameList) - - end do ! end of nloop - - ! ---------------------- - ! close the file - ! ---------------------- - - call pio_freedecomp(File,iodesc) - call cam_pio_closefile(File) - - end subroutine cam_write_srfrest - - !========================================================================== - subroutine cam_write_clockrest(clock, yr_spec, mon_spec, day_spec, & - sec_spec, rc) - - ! When there is no mediator, the driver needs to have - ! restart information to start up - ! This routine writes this out and the driver reads it - ! back in on a restart run - - ! Arguments - type(ESMF_Clock), intent(in) :: clock - integer, intent(in) :: yr_spec ! Simulation year - integer, intent(in) :: mon_spec ! Simulation month - integer, intent(in) :: day_spec ! Simulation day - integer, intent(in) :: sec_spec ! Seconds into current simulation day - integer, intent(out) :: rc ! error code - - ! Local variables - type(ESMF_Time) :: startTime - type(ESMF_Time) :: currTime - type(ESMF_Time) :: nextTime - integer :: unitn - type(file_desc_t) :: File - integer :: start_ymd - integer :: start_tod - integer :: curr_ymd - integer :: curr_tod - integer :: yy,mm,dd ! Temporaries for time query - type(var_desc_t) :: varid_start_ymd - type(var_desc_t) :: varid_start_tod - type(var_desc_t) :: varid_curr_ymd - type(var_desc_t) :: varid_curr_tod - integer :: rcode - character(ESMF_MAXSTR) :: restart_pfile - character(ESMF_MAXSTR) :: restart_file - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! Get properties from clock - call ESMF_ClockGet(clock, startTime=startTime, currTime=currTime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call ESMF_ClockGetNextTime(clock, nextTime=nextTime, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - call ESMF_TimeGet(startTime, yy=yy, mm=mm, dd=dd, s=start_tod, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call shr_cal_ymd2date(yy,mm,dd,start_ymd) - - call ESMF_TimeGet(nextTime, yy=yy, mm=mm, dd=dd, s=curr_tod, rc=rc) - !call ESMF_TimeGet(currTime, yy=yy, mm=mm, dd=dd, s=curr_tod, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - call shr_cal_ymd2date(yy,mm,dd,curr_ymd) - - ! Open clock info restart dataset - restart_file = interpret_filename_spec('%c.cpl.r.%y-%m-%d-%s.nc', & - yr_spec=yr_spec, mon_spec=mon_spec, day_spec=day_spec, & - sec_spec=sec_spec) - - if (masterproc) then - write(iulog,*) " In this configuration, there is no mediator" - write(iulog,*) " Normally, the mediator restart file provides ", & - "the restart time info" - write(iulog,*) " In this case, CAM will create the ", & - "rpointer.cpl and cpl restart file" - write(iulog,*) " containing this information" - write(iulog,*) " writing rpointer file for driver clock info, ", & - "rpointer.cpl" - write(iulog,*) " writing restart clock info for driver= ", & - trim(restart_file) - open(newunit=unitn, file='rpointer.cpl', form='FORMATTED') - write(unitn,'(a)') trim(restart_file) - close(unitn) - end if - - call cam_pio_createfile(File, trim(restart_file), 0) - rcode = pio_def_var(File, 'start_ymd', PIO_INT, varid_start_ymd) - rcode = pio_def_var(File, 'start_tod', PIO_INT, varid_start_tod) - rcode = pio_def_var(File, 'curr_ymd', PIO_INT, varid_curr_ymd) - rcode = pio_def_var(File, 'curr_tod', PIO_INT, varid_curr_tod) - rcode = pio_enddef(File) - rcode = pio_put_var(File, varid_start_ymd, start_ymd) - rcode = pio_put_var(File, varid_start_tod, start_tod) - rcode = pio_put_var(File, varid_curr_ymd, curr_ymd) - rcode = pio_put_var(File, varid_curr_tod, curr_tod) - call cam_pio_closefile(File) - - end subroutine cam_write_clockrest - - !========================================================================== - subroutine cam_set_mesh_for_single_column(scol_lon, scol_lat, mesh, rc) - ! Generate a mesh for single column - - ! Dummy arguments - real(r8), intent(in) :: scol_lon - real(r8), intent(in) :: scol_lat - type(ESMF_Mesh), intent(out) :: mesh - integer, intent(out) :: rc - - ! Local variables - type(ESMF_Grid) :: lgrid - integer :: maxIndex(2) - real(r8) :: mincornerCoord(2) - real(r8) :: maxcornerCoord(2) - character(len=*), parameter :: subname= ' (cam_set_mesh_for_single_column) ' - !----------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! Use center and come up with arbitrary area delta lon and lat = .1 degree - maxIndex(1) = 1 ! number of lons - maxIndex(2) = 1 ! number of lats - mincornerCoord(1) = scol_lon - .1_r8 ! min lon - mincornerCoord(2) = scol_lat - .1_r8 ! min lat - maxcornerCoord(1) = scol_lon + .1_r8 ! max lon - maxcornerCoord(2) = scol_lat + .1_r8 ! max lat - - ! create the ESMF grid - lgrid = ESMF_GridCreateNoPeriDimUfrm(maxindex=maxindex, & - mincornercoord=mincornercoord, maxcornercoord= maxcornercoord, & - staggerloclist=(/ESMF_STAGGERLOC_CENTER, ESMF_STAGGERLOC_CORNER/), & - rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - ! create the mesh from the lgrid - mesh = ESMF_MeshCreate(lgrid, rc=rc) - if (ChkErr(rc, __LINE__, u_FILE_u)) return - - end subroutine cam_set_mesh_for_single_column + !-------------------------------- + ! Reset shr logging to my original values + !-------------------------------- + + call shr_log_setLogUnit (shrlogunit) + + end subroutine ModelAdvance + + !=============================================================================== + + subroutine ModelSetRunClock(gcomp, rc) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + type(ESMF_Clock) :: mclock, dclock + type(ESMF_Time) :: mcurrtime, dcurrtime + type(ESMF_Time) :: mstoptime + type(ESMF_TimeInterval) :: mtimestep, dtimestep + character(len=256) :: cvalue + character(len=256) :: restart_option ! Restart option units + integer :: restart_n ! Number until restart interval + integer :: restart_ymd ! Restart date (YYYYMMDD) + type(ESMF_ALARM) :: restart_alarm + character(len=256) :: stop_option ! Stop option units + integer :: stop_n ! Number until stop interval + integer :: stop_ymd ! Stop date (YYYYMMDD) + type(ESMF_ALARM) :: stop_alarm + character(len=128) :: name + integer :: alarmcount + character(len=*),parameter :: subname=trim(modName)//':(ModelSetRunClock) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! query the Component for its clocks + call NUOPC_ModelGet(gcomp, driverClock=dclock, modelClock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockGet(dclock, currTime=dcurrtime, timeStep=dtimestep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockGet(mclock, currTime=mcurrtime, timeStep=mtimestep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !-------------------------------- + ! force model clock currtime and timestep to match driver and set stoptime + !-------------------------------- + + mstoptime = mcurrtime + dtimestep + call ESMF_ClockSet(mclock, currTime=dcurrtime, timeStep=dtimestep, stopTime=mstoptime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !-------------------------------- + ! set restart and stop alarms + !-------------------------------- + + call ESMF_ClockGetAlarmList(mclock, alarmlistflag=ESMF_ALARMLIST_ALL, alarmCount=alarmCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (alarmCount == 0) then + + call ESMF_GridCompGet(gcomp, name=name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite(subname//'setting alarms for' // trim(name), ESMF_LOGMSG_INFO) + + !---------------- + ! Restart alarm + !---------------- + call NUOPC_CompAttributeGet(gcomp, name="restart_option", value=restart_option, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="restart_n", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) restart_n + + call NUOPC_CompAttributeGet(gcomp, name="restart_ymd", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) restart_ymd + + call alarmInit(mclock, restart_alarm, restart_option, & + opt_n = restart_n, & + opt_ymd = restart_ymd, & + RefTime = mcurrTime, & + alarmname = 'alarm_restart', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_AlarmSet(restart_alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------- + ! Stop alarm + !---------------- + call NUOPC_CompAttributeGet(gcomp, name="stop_option", value=stop_option, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="stop_n", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_n + + call NUOPC_CompAttributeGet(gcomp, name="stop_ymd", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_ymd + + call alarmInit(mclock, stop_alarm, stop_option, & + opt_n = stop_n, & + opt_ymd = stop_ymd, & + RefTime = mcurrTime, & + alarmname = 'alarm_stop', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_AlarmSet(stop_alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end if + + !-------------------------------- + ! Advance model clock to trigger alarms then reset model clock back to currtime + !-------------------------------- + + call ESMF_ClockAdvance(mclock,rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockSet(mclock, currTime=dcurrtime, timeStep=dtimestep, stopTime=mstoptime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine ModelSetRunClock + + !=============================================================================== + subroutine ModelFinalize(gcomp, rc) + type(ESMF_GridComp) :: gcomp + integer, intent(out) :: rc + + ! local variables + integer :: shrlogunit ! original log unit + character(*), parameter :: F00 = "('(atm_comp_nuopc) ',8a)" + character(*), parameter :: F91 = "('(atm_comp_nuopc) ',73('-'))" + character(len=*),parameter :: subname=trim(modName)//':(ModelFinalize) ' + !------------------------------------------------------------------------------- + + !-------------------------------- + ! Finalize routine + !-------------------------------- + + rc = ESMF_SUCCESS + + call shr_log_getLogUnit (shrlogunit) + call shr_log_setLogUnit (iulog) + + call cam_timestep_final() + call cam_final( cam_out, cam_in ) + + if (masterproc) then + write(iulog,F91) + write(iulog,F00) 'CAM: end of main integration loop' + write(iulog,F91) + end if + + call shr_log_setLogUnit (shrlogunit) + + end subroutine ModelFinalize + + !=============================================================================== + subroutine cam_orbital_init(gcomp, logunit, mastertask, rc) + + !---------------------------------------------------------- + ! Initialize orbital related values + !---------------------------------------------------------- + + ! input/output variables + type(ESMF_GridComp) , intent(in) :: gcomp + integer , intent(in) :: logunit + logical , intent(in) :: mastertask + integer , intent(out) :: rc ! output error + + ! local variables + character(len=CL) :: msgstr ! temporary + character(len=CL) :: cvalue ! temporary + character(len=*) , parameter :: subname = "(cam_orbital_init)" + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Determine orbital attributes from input + call NUOPC_CompAttributeGet(gcomp, name="orb_mode", value=cvalue, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) orb_mode + + call NUOPC_CompAttributeGet(gcomp, name="orb_iyear", value=cvalue, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) orb_iyear + + call NUOPC_CompAttributeGet(gcomp, name="orb_iyear_align", value=cvalue, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) orb_iyear_align + + call NUOPC_CompAttributeGet(gcomp, name="orb_obliq", value=cvalue, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) orb_obliq + + call NUOPC_CompAttributeGet(gcomp, name="orb_eccen", value=cvalue, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) orb_eccen + + call NUOPC_CompAttributeGet(gcomp, name="orb_mvelp", value=cvalue, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) orb_mvelp + + ! Error checks + if (trim(orb_mode) == trim(orb_fixed_year)) then + orb_obliq = SHR_ORB_UNDEF_REAL + orb_eccen = SHR_ORB_UNDEF_REAL + orb_mvelp = SHR_ORB_UNDEF_REAL + if (orb_iyear == SHR_ORB_UNDEF_INT) then + if (mastertask) then + write(logunit,*) trim(subname),' ERROR: invalid settings orb_mode =',trim(orb_mode) + write(logunit,*) trim(subname),' ERROR: fixed_year settings = ',orb_iyear + write (msgstr, *) ' ERROR: invalid settings for orb_mode '//trim(orb_mode) + end if + call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc) + return ! bail out + endif + elseif (trim(orb_mode) == trim(orb_variable_year)) then + orb_obliq = SHR_ORB_UNDEF_REAL + orb_eccen = SHR_ORB_UNDEF_REAL + orb_mvelp = SHR_ORB_UNDEF_REAL + if (orb_iyear == SHR_ORB_UNDEF_INT .or. orb_iyear_align == SHR_ORB_UNDEF_INT) then + if (mastertask) then + write(logunit,*) trim(subname),' ERROR: invalid settings orb_mode =',trim(orb_mode) + write(logunit,*) trim(subname),' ERROR: variable_year settings = ',orb_iyear, orb_iyear_align + write (msgstr, *) subname//' ERROR: invalid settings for orb_mode '//trim(orb_mode) + end if + call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc) + return ! bail out + endif + elseif (trim(orb_mode) == trim(orb_fixed_parameters)) then + !-- force orb_iyear to undef to make sure shr_orb_params works properly + orb_iyear = SHR_ORB_UNDEF_INT + orb_iyear_align = SHR_ORB_UNDEF_INT + if (orb_eccen == SHR_ORB_UNDEF_REAL .or. & + orb_obliq == SHR_ORB_UNDEF_REAL .or. & + orb_mvelp == SHR_ORB_UNDEF_REAL) then + if (mastertask) then + write(logunit,*) trim(subname),' ERROR: invalid settings orb_mode =',trim(orb_mode) + write(logunit,*) trim(subname),' ERROR: orb_eccen = ',orb_eccen + write(logunit,*) trim(subname),' ERROR: orb_obliq = ',orb_obliq + write(logunit,*) trim(subname),' ERROR: orb_mvelp = ',orb_mvelp + write (msgstr, *) subname//' ERROR: invalid settings for orb_mode '//trim(orb_mode) + end if + call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc) + return ! bail out + endif + else + write (msgstr, *) subname//' ERROR: invalid orb_mode '//trim(orb_mode) + call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc) + rc = ESMF_FAILURE + return ! bail out + endif + + end subroutine cam_orbital_init + + !=============================================================================== + subroutine cam_orbital_update(clock, logunit, mastertask, eccen, obliqr, lambm0, mvelpp, rc) + + !---------------------------------------------------------- + ! Update orbital settings + !---------------------------------------------------------- + + ! input/output variables + type(ESMF_Clock) , intent(in) :: clock + integer , intent(in) :: logunit + logical , intent(in) :: mastertask + real(R8) , intent(inout) :: eccen ! orbital eccentricity + real(R8) , intent(inout) :: obliqr ! Earths obliquity in rad + real(R8) , intent(inout) :: lambm0 ! Mean long of perihelion at vernal equinox (radians) + real(R8) , intent(inout) :: mvelpp ! moving vernal equinox longitude of perihelion plus pi (radians) + integer , intent(out) :: rc ! output error + + ! local variables + type(ESMF_Time) :: CurrTime ! current time + integer :: year ! model year at current time + integer :: orb_year ! orbital year for current orbital computation + character(len=CL) :: msgstr ! temporary + logical, save :: logprint = .true. + character(len=*) , parameter :: subname = "(cam_orbital_update)" + !------------------------------------------- + + rc = ESMF_SUCCESS + + if (trim(orb_mode) == trim(orb_variable_year)) then + call ESMF_ClockGet(clock, CurrTime=CurrTime, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeGet(CurrTime, yy=year, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + orb_year = orb_iyear + (year - orb_iyear_align) + else + orb_year = orb_iyear + end if + if(.not. (logprint .and. mastertask)) then + logprint = .false. + endif + + eccen = orb_eccen + + call shr_orb_params(orb_year, eccen, orb_obliq, orb_mvelp, obliqr, lambm0, mvelpp, logprint) + logprint = .false. + if ( eccen == SHR_ORB_UNDEF_REAL .or. obliqr == SHR_ORB_UNDEF_REAL .or. & + mvelpp == SHR_ORB_UNDEF_REAL .or. lambm0 == SHR_ORB_UNDEF_REAL) then + write (msgstr, *) subname//' ERROR: orb params incorrect' + call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc) + return ! bail out + endif + + end subroutine cam_orbital_update + + !=============================================================================== + subroutine cam_read_srfrest( gcomp, clock, rc ) + + ! input/output variables + type(ESMF_GridComp) :: gcomp + type(ESMF_Clock), intent(inout) :: clock + integer , intent(out) :: rc + + ! local variables + type(ESMF_State) :: importState, exportState + type(ESMF_Field) :: lfield + integer :: lrank + integer :: rcode ! return error code + integer :: nf,n + type(file_desc_t) :: file + type(io_desc_t) :: iodesc + integer :: fieldCount + character(ESMF_MAXSTR),allocatable :: fieldNameList(:) + type(var_desc_t) :: varid + real(r8), pointer :: fldptr(:) + real(r8), pointer :: tmpptr(:) + real(r8), pointer :: fldptr2d(:,:) + type(ESMF_Time) :: currTime ! time at previous interval + integer :: yr_spec ! Current year + integer :: mon_spec ! Current month + integer :: day_spec ! Current day + integer :: sec_spec ! Current time of day (sec) + character(len=256) :: fname_srf_cam ! surface restart filename + character(len=256) :: pname_srf_cam ! surface restart full pathname + character(len=PIO_MAX_NAME) :: varname + integer :: ungriddedUBound(1) ! currently the size must equal 1 for rank 2 fieldds + integer :: gridToFieldMap(1) ! currently the size must equal 1 for rank 2 fieldds + integer :: lsize + character(len=8) :: cvalue + integer :: nloop + character(len=4) :: prefix + character(len=*), parameter :: subname = "cam_read_srfrest" + !----------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! ------------------------------ + ! Get surface restart dataset + ! ------------------------------ + + call ESMF_GridCompGet(gcomp, clock=clock, importState=importState, exportState=exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockGet( clock, currTime=currTime, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet( currTime, yy=yr_spec, mm=mon_spec, dd=day_spec, s=sec_spec, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + fname_srf_cam = interpret_filename_spec( rsfilename_spec_cam, case=cam_initfiles_get_caseid(), & + yr_spec=yr_spec, mon_spec=mon_spec, day_spec=day_spec, sec_spec= sec_spec ) + pname_srf_cam = trim(cam_initfiles_get_restdir() )//fname_srf_cam + call cam_get_file(pname_srf_cam, fname_srf_cam) + + ! ------------------------------ + ! Open restart file + ! ------------------------------ + + call cam_pio_openfile(File, fname_srf_cam, 0) + call pio_initdecomp(pio_subsystem, pio_double, (/ngcols/), dof, iodesc) + call pio_seterrorhandling(File, pio_bcast_error) + + ! ------------------------------ + ! Read in import and export fields + ! ------------------------------ + + do nloop = 1,2 + + if (nloop == 1) then + prefix = 'x2a_' ! import fields + call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(fieldnameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(importState, itemNameList=fieldnameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + prefix = 'a2x_' ! export fields + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(fieldnameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(exportState, itemNameList=fieldnameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! Loop over fields in import or export state + do nf = 1,fieldCount + + if (trim(fieldnameList(nf)) == flds_scalar_name) CYCLE + + ! Determine dimension of field + if (nloop == 1) then + call ESMF_StateGet(importState, itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call ESMF_StateGet(exportState, itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + call ESMF_FieldGet(lfield, rank=lrank, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + if (lrank == 1) then + + call ESMF_FieldGet(lfield, farrayPtr=fldptr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + varname = trim(prefix)//trim(fieldnameList(nf)) + rcode = pio_inq_varid(File,trim(varname) ,varid) + if (rcode == pio_noerr) then + call pio_read_darray(File, varid, iodesc, fldptr, rcode) + else + if (masterproc) then + write(iulog,*)'cam_read_srfrest warning: field ',trim(varname),' is not on restart file' + write(iulog,*)'for backwards compatibility will set it to 0' + end if + fldptr(:) = 0._r8 + end if + + else if (lrank == 2) then + + ! There is an output variable for each element of the undistributed dimension + call ESMF_FieldGet(lfield, ungriddedUBound=ungriddedUBound, gridToFieldMap=gridToFieldMap, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(lfield, farrayPtr=fldptr2d, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (gridToFieldMap(1) == 1) then + lsize = size(fldptr2d, dim=1) + else if (gridToFieldMap(1) == 2) then + lsize = size(fldptr2d, dim=2) + end if + + allocate(tmpptr(lsize), stat=ierr) + call check_allocate(ierr, subname, 'tmpptr(lsize)', & + file=__FILE__, line=__LINE__) + do n = 1,ungriddedUBound(1) + write(cvalue,'(i0)') n + varname = trim(prefix)//trim(fieldnameList(nf))//trim(cvalue) + rcode = pio_inq_varid(File,trim(varname) ,varid) + + if (rcode == pio_noerr) then + call pio_read_darray(File, varid, iodesc, tmpptr, rcode) + else + if (masterproc) then + write(iulog,*)'cam_read_srfrest warning: field ',trim(varname),' is not on restart file' + write(iulog,*)'for backwards compatibility will set it to 0' + end if + tmpptr(:) = 0._r8 + end if + if (gridToFieldMap(1) == 1) then + fldptr2d(:,n) = tmpptr(:) + else if (gridToFieldMap(1) == 2) then + fldptr2d(n,:) = tmpptr(:) + end if + end do + deallocate(tmpptr) + + end if ! end lrank if block + end do + deallocate(fieldnameList) + end do + + ! ------------------------------ + ! Close file + ! ------------------------------ + + call pio_seterrorhandling(File, pio_internal_error) + call pio_freedecomp(File, iodesc) + call cam_pio_closefile(File) + + end subroutine cam_read_srfrest + + !=========================================================================================== + subroutine cam_write_srfrest( gcomp, yr_spec, mon_spec, day_spec, sec_spec, rc ) + + ! Arguments + type(ESMF_GridComp) :: gcomp + integer , intent(in) :: yr_spec ! Simulation year + integer , intent(in) :: mon_spec ! Simulation month + integer , intent(in) :: day_spec ! Simulation day + integer , intent(in) :: sec_spec ! Seconds into current simulation day + integer , intent(out) :: rc ! error code + + ! Local variables + type(ESMF_State) :: importState, exportState + type(ESMF_Field) :: lField + integer :: lrank + integer :: rcode ! return error code + integer :: dimid(1), nf, n + type(file_desc_t) :: file + type(io_desc_t) :: iodesc + integer :: fieldCount + character(ESMF_MAXSTR),allocatable :: fieldnameList(:) + type(var_desc_t) :: varid + real(r8), pointer :: fldptr1d(:) + real(r8), pointer :: fldptr2d(:,:) + character(len=PIO_MAX_NAME) :: varname + character(len=256) :: fname_srf_cam ! surface restart filename + character(len=8) :: cvalue + integer :: nloop + character(len=4) :: prefix + integer :: ungriddedUBound(1) ! currently the size must equal 1 for rank 2 fieldds + integer :: gridToFieldMap(1) ! currently the size must equal 1 for rank 2 fieldds + character(len=*), parameter :: subname = "cam_write_srfrest" + !----------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! ---------------------- + ! Get import and export states + ! ---------------------- + + call ESMF_GridCompGet(gcomp, importState=importState, exportState=exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! ---------------------- + ! Open surface restart dataset + ! ---------------------- + + fname_srf_cam = interpret_filename_spec( rsfilename_spec_cam, & + yr_spec=yr_spec, mon_spec=mon_spec, day_spec=day_spec, sec_spec= sec_spec ) + + call cam_pio_createfile(File, fname_srf_cam, 0) + call pio_initdecomp(pio_subsystem, pio_double, (/ngcols/), dof, iodesc) + + ! ---------------------- + ! Define dimensions + ! ---------------------- + + rcode = pio_def_dim(File, 'x2a_nx', ngcols, dimid(1)) + rcode = pio_def_dim(File, 'a2x_nx', ngcols, dimid(1)) + + ! ---------------------- + ! Define import and export variable ids + ! ---------------------- + + do nloop = 1,2 + + if (nloop == 1) then + prefix = 'x2a_' ! import fields + call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(fieldNameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(importState, itemNameList=fieldNameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + prefix = 'a2x_' ! export fields + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(fieldNameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(exportState, itemNameList=fieldNameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + do nf = 1,fieldCount + + if (trim(fieldNameList(nf)) == flds_scalar_name) CYCLE + + if (nloop == 1) then + call ESMF_StateGet(importState, itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call ESMF_StateGet(exportState, itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + call ESMF_FieldGet(lfield, rank=lrank, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + if (lrank == 1) then + + varname = trim(prefix)//trim(fieldNameList(nf)) + rcode = pio_def_var(File,trim(varname), PIO_DOUBLE, dimid, varid) + rcode = pio_put_att(File, varid, "_fillvalue", fillvalue) + + else if (lrank == 2) then + + ! Determine the size of the ungridded dimension and the + ! index where the undistributed dimension is located + call ESMF_FieldGet(lfield, ungriddedUBound=ungriddedUBound, gridToFieldMap=gridToFieldMap, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! Output for each ungriddedUbound index + do n = 1,ungriddedUBound(1) + write(cvalue,'(i0)') n + varname = trim(prefix)//trim(fieldNameList(nf))//trim(cvalue) + rcode = pio_def_var(File,trim(varname), PIO_DOUBLE, dimid, varid) + rcode = pio_put_att(File, varid, "_fillvalue", fillvalue) + end do + + end if ! end if-block over rank size + + end do ! end loop over import or export fieldsfields + deallocate(fieldNameList) + end do + + ! ---------------------- + ! End definition phase + ! ---------------------- + + rcode = pio_enddef(File) ! don't check return code, might be enddef already + + ! ---------------------- + ! Write the restart data for the import fields and export fields + ! ---------------------- + + do nloop = 1,2 + + if (nloop == 1) then + prefix = 'x2a_' ! import fields + call ESMF_StateGet(importState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(fieldNameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(importState, itemNameList=fieldNameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + prefix = 'a2x_' ! export fields + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(fieldNameList(fieldCount), stat=ierr) + call check_allocate(ierr, subname, 'fieldNameList(fieldCount)', & + file=__FILE__, line=__LINE__) + call ESMF_StateGet(exportState, itemNameList=fieldNameList, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + do nf = 1,fieldCount + + if (trim(fieldNameList(nf)) == flds_scalar_name) CYCLE + + if (nloop == 1) then + call ESMF_StateGet(importState, itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call ESMF_StateGet(exportState, itemName=trim(fieldnameList(nf)), field=lfield, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + call ESMF_FieldGet(lfield, rank=lrank, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + if (lrank == 1) then + + varname = trim(prefix)//trim(fieldNameList(nf)) + rcode = pio_inq_varid(File, trim(varname), varid) + call ESMF_FieldGet(lfield, farrayPtr=fldptr1d, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call pio_write_darray(File, varid, iodesc, fldptr1d, rcode) + + else if (lrank == 2) then + + ! There is an output variable for each element of the undistributed dimension + call ESMF_FieldGet(lfield, ungriddedUBound=ungriddedUBound, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(lfield, farrayPtr=fldptr2d, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + do n = 1,ungriddedUBound(1) + write(cvalue,'(i0)') n + varname = trim(prefix)//trim(fieldNameList(nf))//trim(cvalue) + rcode = pio_inq_varid(File, trim(varname), varid) + if (gridToFieldMap(1) == 1) then + call pio_write_darray(File, varid, iodesc, fldptr2d(:,n), rcode, fillval=fillvalue) + else if (gridToFieldMap(1) == 2) then + call pio_write_darray(File, varid, iodesc, fldptr2d(n,:), rcode, fillval=fillvalue) + end if + end do + + end if + end do ! end loop over import or export fields + deallocate(fieldNameList) + + end do ! end of nloop + + ! ---------------------- + ! close the file + ! ---------------------- + + call pio_freedecomp(File,iodesc) + call cam_pio_closefile(File) + + end subroutine cam_write_srfrest + + !=============================================================================== + subroutine cam_write_clockrest( clock, yr_spec, mon_spec, day_spec, sec_spec, rc ) + + ! When there is no mediator, the driver needs to have restart information to start up + ! This routine writes this out and the driver reads it back in on a restart run + + ! Arguments + type(ESMF_Clock) , intent(in) :: clock + integer , intent(in) :: yr_spec ! Simulation year + integer , intent(in) :: mon_spec ! Simulation month + integer , intent(in) :: day_spec ! Simulation day + integer , intent(in) :: sec_spec ! Seconds into current simulation day + integer , intent(out) :: rc ! error code + + ! Local variables + type(ESMF_Time) :: startTime + type(ESMF_Time) :: currTime + type(ESMF_Time) :: nextTime + integer :: unitn + type(file_desc_t) :: File + integer :: start_ymd + integer :: start_tod + integer :: curr_ymd + integer :: curr_tod + integer :: yy,mm,dd ! Temporaries for time query + type(var_desc_t) :: varid_start_ymd + type(var_desc_t) :: varid_start_tod + type(var_desc_t) :: varid_curr_ymd + type(var_desc_t) :: varid_curr_tod + integer :: rcode + character(ESMF_MAXSTR) :: restart_pfile + character(ESMF_MAXSTR) :: restart_file + !----------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Get properties from clock + call ESMF_ClockGet( clock, startTime=startTime, currTime=currTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGetNextTime(clock, nextTime=nextTime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet( startTime, yy=yy, mm=mm, dd=dd, s=start_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yy,mm,dd,start_ymd) + + call ESMF_TimeGet( nextTime, yy=yy, mm=mm, dd=dd, s=curr_tod, rc=rc ) + !call ESMF_TimeGet( currTime, yy=yy, mm=mm, dd=dd, s=curr_tod, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_cal_ymd2date(yy,mm,dd,curr_ymd) + + ! Open clock info restart dataset + restart_file = interpret_filename_spec( '%c.cpl.r.%y-%m-%d-%s.nc', & + yr_spec=yr_spec, mon_spec=mon_spec, day_spec=day_spec, sec_spec= sec_spec ) + + if (masterproc) then + write(iulog,*) " In this configuration, there is no mediator" + write(iulog,*) " Normally, the mediator restart file provides the restart time info" + write(iulog,*) " In this case, CAM will create the rpointer.cpl and cpl restart file" + write(iulog,*) " containing this information" + write(iulog,*) " writing rpointer file for driver clock info, rpointer.cpl" + write(iulog,*) " writing restart clock info for driver= "//trim(restart_file) + open(newunit=unitn, file='rpointer.cpl', form='FORMATTED') + write(unitn,'(a)') trim(restart_file) + close(unitn) + endif + + call cam_pio_createfile(File, trim(restart_file), 0) + rcode = pio_def_var(File, 'start_ymd', PIO_INT, varid_start_ymd) + rcode = pio_def_var(File, 'start_tod', PIO_INT, varid_start_tod) + rcode = pio_def_var(File, 'curr_ymd' , PIO_INT, varid_curr_ymd) + rcode = pio_def_var(File, 'curr_tod' , PIO_INT, varid_curr_tod) + rcode = pio_enddef(File) + rcode = pio_put_var(File, varid_start_ymd, start_ymd) + rcode = pio_put_var(File, varid_start_tod, start_tod) + rcode = pio_put_var(File, varid_curr_ymd, curr_ymd) + rcode = pio_put_var(File, varid_curr_tod, curr_tod) + call cam_pio_closefile(File) + + end subroutine cam_write_clockrest + + !=============================================================================== + subroutine cam_set_mesh_for_single_column(scol_lon, scol_lat, mesh, rc) + + ! Generate a mesh for single column + use netcdf + + ! input/output variables + real(r8) , intent(in) :: scol_lon + real(r8) , intent(in) :: scol_lat + type(ESMF_Mesh) , intent(out) :: mesh + integer , intent(out) :: rc + + ! local variables + type(ESMF_Grid) :: lgrid + integer :: maxIndex(2) + real(r8) :: mincornerCoord(2) + real(r8) :: maxcornerCoord(2) + character(len=*), parameter :: subname= ' (lnd_set_mesh_for_single_column) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Use center and come up with arbitrary area delta lon and lat = .1 degree + maxIndex(1) = 1 ! number of lons + maxIndex(2) = 1 ! number of lats + mincornerCoord(1) = scol_lon - .1_r8 ! min lon + mincornerCoord(2) = scol_lat - .1_r8 ! min lat + maxcornerCoord(1) = scol_lon + .1_r8 ! max lon + maxcornerCoord(2) = scol_lat + .1_r8 ! max lat + + ! create the ESMF grid + lgrid = ESMF_GridCreateNoPeriDimUfrm (maxindex=maxindex, & + mincornercoord=mincornercoord, maxcornercoord= maxcornercoord, & + staggerloclist=(/ESMF_STAGGERLOC_CENTER, ESMF_STAGGERLOC_CORNER/), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! create the mesh from the lgrid + mesh = ESMF_MeshCreate(lgrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine cam_set_mesh_for_single_column + + !=============================================================================== + subroutine cam_pio_checkerr(ierror, description) + use pio, only : PIO_NOERR + integer , intent(in) :: ierror + character(*), intent(in) :: description + if (ierror /= PIO_NOERR) then + write (*,'(6a)') 'ERROR ', trim(description) + call shr_sys_abort() + endif + end subroutine cam_pio_checkerr end module atm_comp_nuopc diff --git a/src/cpl/nuopc/atm_import_export.F90 b/src/cpl/nuopc/atm_import_export.F90 index 0c074139..733e93d5 100644 --- a/src/cpl/nuopc/atm_import_export.F90 +++ b/src/cpl/nuopc/atm_import_export.F90 @@ -1,38 +1,25 @@ module atm_import_export - use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise, NUOPC_IsConnected - use NUOPC_Model , only : NUOPC_ModelGet - use ESMF , only : ESMF_GridComp, ESMF_State, ESMF_Mesh, ESMF_StateGet - use ESMF , only : ESMF_KIND_R8, ESMF_SUCCESS, ESMF_MAXSTR, ESMF_LOGMSG_INFO - use ESMF , only : ESMF_LogWrite, ESMF_LOGMSG_ERROR, ESMF_LogFoundError - use ESMF , only : ESMF_STATEITEM_NOTFOUND, ESMF_StateItem_Flag - use ESMF , only : operator(/=), operator(==) - use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs, cx=>shr_kind_cx - use shr_sys_mod , only : shr_sys_abort - use nuopc_shr_methods , only : chkerr - use cam_logfile , only : iulog - use srf_field_check , only : set_active_Sl_ram1 - use srf_field_check , only : set_active_Sl_fv - use srf_field_check , only : set_active_Sl_soilw - use srf_field_check , only : set_active_Fall_flxdst1 - use srf_field_check , only : set_active_Fall_flxvoc - use srf_field_check , only : set_active_Fall_flxfire - use srf_field_check , only : set_active_Fall_fco2_lnd - use srf_field_check , only : set_active_Faoo_fco2_ocn - use srf_field_check , only : set_active_Faxa_nhx - use srf_field_check , only : set_active_Faxa_noy + use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise, NUOPC_IsConnected + use NUOPC_Model , only : NUOPC_ModelGet + use ESMF , only : ESMF_GridComp, ESMF_State, ESMF_Mesh, ESMF_StateGet, ESMF_Field + use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO + use ESMF , only : ESMF_LogWrite + use ESMF , only : operator(/=), operator(==) + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs, cx=>shr_kind_cx implicit none private ! except + public :: read_surface_fields_namelists public :: advertise_fields public :: realize_fields public :: import_fields public :: export_fields - public :: state_getfldptr private :: fldlist_add private :: fldlist_realize + private :: state_getfldptr type fldlist_type character(len=128) :: stdname @@ -46,31 +33,68 @@ module atm_import_export type (fldlist_type) , public, protected :: fldsToAtm(fldsMax) type (fldlist_type) , public, protected :: fldsFrAtm(fldsMax) - character(len=cx) :: carma_fields ! list of CARMA fields from lnd->atm - integer :: drydep_nflds ! number of dry deposition velocity fields lnd-> atm - integer :: megan_nflds ! number of MEGAN voc fields from lnd-> atm - integer :: emis_nflds ! number of fire emission fields from lnd-> atm - integer, public :: ndep_nflds ! number of nitrogen deposition fields from atm->lnd/ocn - integer :: dbug_flag = 0 ! ESMF log output - integer, parameter :: debug_import = 0 ! internal debug level - integer, parameter :: debug_export = 0 ! internal debug level + ! area correction factors for fluxes send and received from mediator + real(r8), allocatable :: mod2med_areacor(:) + real(r8), allocatable :: med2mod_areacor(:) + + character(len=cx) :: carma_fields = ' ' ! list of CARMA fields from lnd->atm + integer :: drydep_nflds = -huge(1) ! number of dry deposition velocity fields lnd-> atm + integer :: megan_nflds = -huge(1) ! number of MEGAN voc fields from lnd-> atm + integer :: emis_nflds = -huge(1) ! number of fire emission fields from lnd-> atm + integer, public :: ndep_nflds = -huge(1) ! number of nitrogen deposition fields from atm->lnd/ocn + logical :: atm_provides_lightning = .false. ! cld to grnd lightning flash freq (min-1) character(*),parameter :: F01 = "('(cam_import_export) ',a,i8,2x,i8,2x,d21.14)" character(*),parameter :: F02 = "('(cam_import_export) ',a,i8,2x,i8,2x,i8,2x,d21.14)" - character(*),parameter :: u_FILE_u = & - __FILE__ + character(*),parameter :: u_FILE_u = __FILE__ !=============================================================================== contains !=============================================================================== - subroutine advertise_fields(gcomp, flds_scalar_name, rc) + !----------------------------------------------------------- + ! read mediator fields namelist file + !----------------------------------------------------------- + subroutine read_surface_fields_namelists() - use spmd_utils , only : masterproc - use seq_drydep_mod , only : seq_drydep_readnl + use shr_drydep_mod , only : shr_drydep_readnl use shr_megan_mod , only : shr_megan_readnl use shr_fire_emis_mod , only : shr_fire_emis_readnl use shr_carma_mod , only : shr_carma_readnl use shr_ndep_mod , only : shr_ndep_readnl + use shr_lightning_coupling_mod, only : shr_lightning_coupling_readnl + + character(len=*), parameter :: nl_file_name = 'drv_flds_in' + + ! read mediator fields options + call shr_ndep_readnl(nl_file_name, ndep_nflds) + call shr_drydep_readnl(nl_file_name, drydep_nflds) + call shr_megan_readnl(nl_file_name, megan_nflds) + call shr_fire_emis_readnl(nl_file_name, emis_nflds) + call shr_carma_readnl(nl_file_name, carma_fields) + call shr_lightning_coupling_readnl(nl_file_name, atm_provides_lightning) + + end subroutine read_surface_fields_namelists + + !----------------------------------------------------------- + ! advertise fields + !----------------------------------------------------------- + subroutine advertise_fields(gcomp, flds_scalar_name, rc) + + ! use statements + use ESMF , only : ESMF_MAXSTR + use nuopc_shr_methods , only : chkerr + use srf_field_check , only : set_active_Sl_ram1 + use srf_field_check , only : set_active_Sl_fv + use srf_field_check , only : set_active_Sl_soilw + use srf_field_check , only : set_active_Fall_flxdst1 + use srf_field_check , only : set_active_Fall_flxvoc + use srf_field_check , only : set_active_Fall_flxfire + use srf_field_check , only : set_active_Fall_fco2_lnd + use srf_field_check , only : set_active_Faoo_fco2_ocn + use srf_field_check , only : set_active_Faxa_nhx + use srf_field_check , only : set_active_Faxa_noy + use spmd_utils , only : masterproc + use cam_logfile , only : iulog ! input/output variables type(ESMF_GridComp) :: gcomp @@ -82,18 +106,15 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) type(ESMF_State) :: exportState character(ESMF_MAXSTR) :: stdname character(ESMF_MAXSTR) :: cvalue - character(len=2) :: nec_str integer :: n, num logical :: flds_co2a ! use case logical :: flds_co2b ! use case logical :: flds_co2c ! use case - integer :: ndep_nflds, megan_nflds, emis_nflds character(len=128) :: fldname character(len=*), parameter :: subname='(atm_import_export:advertise_fields)' !------------------------------------------------------------------------------- rc = ESMF_SUCCESS - call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) call NUOPC_ModelGet(gcomp, importState=importState, exportState=exportState, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -105,25 +126,25 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) call NUOPC_CompAttributeGet(gcomp, name='flds_co2a', value=cvalue, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return read(cvalue,*) flds_co2a - call ESMF_LogWrite(trim(subname)//'flds_co2a = '// trim(cvalue), ESMF_LOGMSG_INFO) + if (masterproc) write(iulog,'(a)') trim(subname)//'flds_co2a = '// trim(cvalue) call NUOPC_CompAttributeGet(gcomp, name='flds_co2b', value=cvalue, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return read(cvalue,*) flds_co2b - call ESMF_LogWrite(trim(subname)//'flds_co2b = '// trim(cvalue), ESMF_LOGMSG_INFO) + if (masterproc) write(iulog,'(a)') trim(subname)//'flds_co2b = '// trim(cvalue) call NUOPC_CompAttributeGet(gcomp, name='flds_co2c', value=cvalue, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return read(cvalue,*) flds_co2c - call ESMF_LogWrite(trim(subname)//'flds_co2c = '// trim(cvalue), ESMF_LOGMSG_INFO) + if (masterproc) write(iulog,'(a)') trim(subname)//'flds_co2c = '// trim(cvalue) !-------------------------------- ! Export fields !-------------------------------- - call ESMF_LogWrite(trim(subname)//' export fields', ESMF_LOGMSG_INFO) - call fldlist_add(fldsFrAtm_num, fldsFrAtm, trim(flds_scalar_name)) + if (masterproc) write(iulog,'(a)') trim(subname)//'export_fields ' + call fldlist_add(fldsFrAtm_num, fldsFrAtm, trim(flds_scalar_name)) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_topo' ) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_z' ) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_u' ) @@ -134,6 +155,7 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_pbot' ) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_dens' ) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_pslv' ) + call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_o3' ) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Faxa_rainc' ) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Faxa_rainl' ) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Faxa_snowc' ) @@ -169,16 +191,25 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_co2diag' ) end if - ! from atm - nitrogen deposition - call shr_ndep_readnl("drv_flds_in", ndep_nflds) if (ndep_nflds > 0) then - call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=ndep_nflds) + ! The following is when CAM/WACCM computes ndep call set_active_Faxa_nhx(.true.) call set_active_Faxa_noy(.true.) + else + ! The following is used for reading in stream data + call set_active_Faxa_nhx(.false.) + call set_active_Faxa_noy(.false.) + end if + ! Assume that 2 fields are always sent as part of Faxa_ndep + call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=2) + + ! lightning flash freq + if (atm_provides_lightning) then + call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_lightning') end if ! Now advertise above export fields - call ESMF_LogWrite(trim(subname)//' advertise export fields ', ESMF_LOGMSG_INFO) + if (masterproc) write(iulog,*) trim(subname)//' advertise export fields' do n = 1,fldsFrAtm_num call NUOPC_Advertise(exportState, standardName=fldsFrAtm(n)%stdname, & TransferOfferGeomObject='will provide', rc=rc) @@ -189,10 +220,9 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) ! Import fields !----------------- - call ESMF_LogWrite(trim(subname)//' Import Fields', ESMF_LOGMSG_INFO) + if (masterproc) write(iulog,'(a)') trim(subname)//' import fields ' call fldlist_add(fldsToAtm_num, fldsToAtm, trim(flds_scalar_name)) - call fldlist_add(fldsToAtm_num, fldsToAtm, 'Sx_anidr' ) call fldlist_add(fldsToAtm_num, fldsToAtm, 'Sx_avsdf' ) call fldlist_add(fldsToAtm_num, fldsToAtm, 'Sx_anidf' ) @@ -210,7 +240,10 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) call fldlist_add(fldsToAtm_num, fldsToAtm, 'Si_snowh' ) call fldlist_add(fldsToAtm_num, fldsToAtm, 'So_ssq' ) call fldlist_add(fldsToAtm_num, fldsToAtm, 'So_re' ) + call fldlist_add(fldsToAtm_num, fldsToAtm, 'So_ustar' ) call fldlist_add(fldsToAtm_num, fldsToAtm, 'Sx_u10' ) + call fldlist_add(fldsToAtm_num, fldsToAtm, 'So_ugustOut') + call fldlist_add(fldsToAtm_num, fldsToAtm, 'So_u10withGust') call fldlist_add(fldsToAtm_num, fldsToAtm, 'Faxx_taux' ) call fldlist_add(fldsToAtm_num, fldsToAtm, 'Faxx_tauy' ) call fldlist_add(fldsToAtm_num, fldsToAtm, 'Faxx_lat' ) @@ -232,40 +265,30 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) call set_active_Faoo_fco2_ocn(.true.) end if - call ESMF_LogWrite(trim(subname)//' here1', ESMF_LOGMSG_INFO) ! dry deposition velocities from land - ALSO initialize drydep here - call seq_drydep_readnl("drv_flds_in", drydep_nflds) if (drydep_nflds > 0) then call fldlist_add(fldsToAtm_num, fldsToAtm, 'Sl_ddvel', ungridded_lbound=1, ungridded_ubound=drydep_nflds) end if - call ESMF_LogWrite(trim(subname)//' here2', ESMF_LOGMSG_INFO) ! MEGAN VOC emissions fluxes from land - call shr_megan_readnl('drv_flds_in', megan_nflds) if (megan_nflds > 0) then call fldlist_add(fldsToAtm_num, fldsToAtm, 'Fall_voc', ungridded_lbound=1, ungridded_ubound=megan_nflds) call set_active_Fall_flxvoc(.true.) end if - call ESMF_LogWrite(trim(subname)//' here3', ESMF_LOGMSG_INFO) ! fire emissions fluxes from land - call shr_fire_emis_readnl('drv_flds_in', emis_nflds) if (emis_nflds > 0) then call fldlist_add(fldsToAtm_num, fldsToAtm, 'Fall_fire', ungridded_lbound=1, ungridded_ubound=emis_nflds) call fldlist_add(fldsToAtm_num, fldsToAtm, 'Sl_fztop') call set_active_Fall_flxfire(.true.) end if - call ESMF_LogWrite(trim(subname)//' here4', ESMF_LOGMSG_INFO) ! CARMA volumetric soil water from land - call shr_carma_readnl('drv_flds_in', carma_fields) if (carma_fields /= ' ') then call fldlist_add(fldsToAtm_num, fldsToAtm, 'Sl_soilw') ! optional for carma call set_active_Sl_soilw(.true.) ! check for carma end if - call ESMF_LogWrite(trim(subname)//' here5', ESMF_LOGMSG_INFO) - ! ------------------------------------------ ! Now advertise above import fields ! ------------------------------------------ @@ -276,24 +299,50 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return enddo - call ESMF_LogWrite(trim(subname)//' done', ESMF_LOGMSG_INFO) - end subroutine advertise_fields !=============================================================================== - subroutine realize_fields(gcomp, Emesh, flds_scalar_name, flds_scalar_num, rc) + subroutine realize_fields(gcomp, Emesh, flds_scalar_name, flds_scalar_num, single_column, rc) + + use ESMF , only : ESMF_MeshGet, ESMF_StateGet + use ESMF , only : ESMF_FieldRegridGetArea,ESMF_FieldGet + use nuopc_shr_methods , only : chkerr + use shr_mpi_mod , only : shr_mpi_min, shr_mpi_max + use spmd_utils , only : masterproc, mpicom + use physics_grid , only : get_area_p + use cam_abortutils , only : check_allocate + use cam_logfile , only : iulog ! input/output variables type(ESMF_GridComp) , intent(inout) :: gcomp type(ESMF_Mesh) , intent(in) :: Emesh character(len=*) , intent(in) :: flds_scalar_name integer , intent(in) :: flds_scalar_num + logical , intent(in) :: single_column integer , intent(out) :: rc ! local variables - type(ESMF_State) :: importState - type(ESMF_State) :: exportState + type(ESMF_State) :: importState + type(ESMF_State) :: exportState + type(ESMF_Field) :: lfield + integer :: numOwnedElements + integer :: n, ierr + real(r8), allocatable :: mesh_areas(:) + real(r8), pointer :: dataptr(:) + real(r8) :: max_mod2med_areacor + real(r8) :: max_med2mod_areacor + real(r8) :: min_mod2med_areacor + real(r8) :: min_med2mod_areacor + real(r8) :: max_mod2med_areacor_glob + real(r8) :: max_med2mod_areacor_glob + real(r8) :: min_mod2med_areacor_glob + real(r8) :: min_med2mod_areacor_glob + character(len=cl) :: cvalue + character(len=cl) :: mesh_atm + character(len=cl) :: mesh_lnd + character(len=cl) :: mesh_ocn + logical :: samegrid_atm_lnd_ocn character(len=*), parameter :: subname='(atm_import_export:realize_fields)' !--------------------------------------------------------------------------- @@ -324,6 +373,78 @@ subroutine realize_fields(gcomp, Emesh, flds_scalar_name, flds_scalar_num, rc) mesh=Emesh, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! Determine if atm/lnd/ocn are on the same grid - if so set area correction factors to 1 + call NUOPC_CompAttributeGet(gcomp, name='mesh_atm', value=mesh_atm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_CompAttributeGet(gcomp, name='mesh_lnd', value=mesh_lnd, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call NUOPC_CompAttributeGet(gcomp, name='mesh_ocn', value=mesh_ocn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + samegrid_atm_lnd_ocn = .false. + if ( trim(mesh_lnd) /= 'UNSET' .and. trim(mesh_atm) == trim(mesh_lnd) .and. & + trim(mesh_ocn) /= 'UNSET' .and. trim(mesh_atm) == trim(mesh_ocn)) then + samegrid_atm_lnd_ocn = .true. + elseif ( trim(mesh_lnd) == 'UNSET' .and. trim(mesh_atm) == trim(mesh_ocn)) then + samegrid_atm_lnd_ocn = .true. + elseif ( trim(mesh_ocn) == 'UNSET' .and. trim(mesh_atm) == trim(mesh_lnd)) then + samegrid_atm_lnd_ocn = .true. + end if + + ! allocate area correction factors + call ESMF_MeshGet(Emesh, numOwnedElements=numOwnedElements, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate (mod2med_areacor(numOwnedElements), stat=ierr) + call check_allocate(ierr, subname, 'mod2med_areacor(numOwnedElements)', & + file=__FILE__, line=__LINE__) + allocate (med2mod_areacor(numOwnedElements), stat=ierr) + call check_allocate(ierr, subname, 'med2mod_areacor(numOwnedElements)', & + file=__FILE__, line=__LINE__) + + if (single_column .or. samegrid_atm_lnd_ocn) then + + mod2med_areacor(:) = 1._r8 + med2mod_areacor(:) = 1._r8 + + else + + ! Determine areas for regridding + call ESMF_StateGet(exportState, itemName=trim(fldsFrAtm(2)%stdname), field=lfield, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldRegridGetArea(lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(lfield, farrayPtr=dataptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(mesh_areas(numOwnedElements), stat=ierr) + call check_allocate(ierr, subname, 'mesh_areas(numOwnedElements)', & + file=__FILE__, line=__LINE__) + mesh_areas(:) = dataptr(:) + + ! Determine flux correction factors (module variables) + do n = 1,numOwnedElements + mod2med_areacor(n) = get_area_p(n) / mesh_areas(n) + med2mod_areacor(n) = 1._r8 / mod2med_areacor(n) + end do + deallocate(mesh_areas) + + end if + + min_mod2med_areacor = minval(mod2med_areacor) + max_mod2med_areacor = maxval(mod2med_areacor) + min_med2mod_areacor = minval(med2mod_areacor) + max_med2mod_areacor = maxval(med2mod_areacor) + call shr_mpi_max(max_mod2med_areacor, max_mod2med_areacor_glob, mpicom) + call shr_mpi_min(min_mod2med_areacor, min_mod2med_areacor_glob, mpicom) + call shr_mpi_max(max_med2mod_areacor, max_med2mod_areacor_glob, mpicom) + call shr_mpi_min(min_med2mod_areacor, min_med2mod_areacor_glob, mpicom) + + if (masterproc) then + write(iulog,'(2A,2g23.15,A )') trim(subname),' : min_mod2med_areacor, max_mod2med_areacor ',& + min_mod2med_areacor_glob, max_mod2med_areacor_glob, 'CAM' + write(iulog,'(2A,2g23.15,A )') trim(subname),' : min_med2mod_areacor, max_med2mod_areacor ',& + min_med2mod_areacor_glob, max_med2mod_areacor_glob, 'CAM' + end if + call ESMF_LogWrite(trim(subname)//' done', ESMF_LOGMSG_INFO) end subroutine realize_fields @@ -334,19 +455,20 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) ! ----------------------------------------------------- ! Set field pointers in import state and - ! copy from field pointer to chunk array data structure + ! copy from field pointer to CAM-SIMA array data structure ! ----------------------------------------------------- - use spmd_utils , only : masterproc use camsrfexch , only : cam_in_t - use physics_grid , only : columns_on_task use shr_const_mod , only : shr_const_stebol -!CAMDEN TODO Need to uncomment these once carbon cycling is enabled in CAMDEN: + use shr_sys_mod , only : shr_sys_abort + use nuopc_shr_methods , only : chkerr +!CAM-SIMA NOTE: Need to uncomment these once carbon cycling is enabled in SIMA. ! use co2_cycle , only : c_i, co2_readFlux_ocn, co2_readFlux_fuel ! use co2_cycle , only : co2_transport, co2_time_interp_ocn, co2_time_interp_fuel ! use co2_cycle , only : data_flux_ocn, data_flux_fuel use physconst , only : mwco2 use time_manager , only : is_first_step, get_nstep + use physics_grid , only : columns_on_task ! input/output variabes type(ESMF_GridComp) :: gcomp @@ -356,8 +478,7 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) ! local variables type(ESMF_State) :: importState - integer :: i,n,c,g, num ! indices - integer :: ncols ! number of columns + integer :: i,n ! loop indices integer :: nstep logical :: overwrite_flds logical :: exists @@ -391,7 +512,6 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) !--------------------------------------------------------------------------- rc = ESMF_SUCCESS - if (dbug_flag > 10) call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) ! Get import state call NUOPC_ModelGet(gcomp, importState=importState, rc=rc) @@ -418,15 +538,11 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getfldptr(importState, 'Faxx_evap', fldptr=fldptr_evap, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%wsx(i) = -fldptr_taux(g) - cam_in(c)%wsy(i) = -fldptr_tauy(g) - cam_in(c)%shf(i) = -fldptr_sen(g) - cam_in(c)%cflx(i,1) = -fldptr_evap(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%wsx(i) = -fldptr_taux(i) * med2mod_areacor(i) + cam_in%wsy(i) = -fldptr_tauy(g) * med2mod_areacor(i) + cam_in%shf(i) = -fldptr_sen(i) * med2mod_areacor(i) + cam_in%cflx(i,1) = -fldptr_evap(i) * med2mod_areacor(i) end do end if ! end of overwrite_flds @@ -462,27 +578,25 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getfldptr(importState, 'Sl_lfrac', fldptr=fldptr_lfrac, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%lhf(i) = -fldptr_lat(g) - cam_in(c)%lwup(i) = -fldptr_lwup(g) - cam_in(c)%asdir(i) = fldptr_avsdr(g) - cam_in(c)%aldir(i) = fldptr_anidr(g) - cam_in(c)%asdif(i) = fldptr_avsdf(g) - cam_in(c)%aldif(i) = fldptr_anidf(g) - cam_in(c)%ts(i) = fldptr_tsurf(g) - cam_in(c)%sst(i) = fldptr_tocn(g) - cam_in(c)%tref(i) = fldptr_tref(g) - cam_in(c)%qref(i) = fldptr_qref(g) - cam_in(c)%u10(i) = fldptr_u10(g) - cam_in(c)%snowhland(i) = fldptr_snowhland(g) - cam_in(c)%snowhice(i) = fldptr_snowhice(g) - cam_in(c)%icefrac(i) = fldptr_ifrac(g) - cam_in(c)%ocnfrac(i) = fldptr_ofrac(g) - cam_in(c)%landfrac(i) = fldptr_lfrac(g) - g = g + 1 - end do + + ! Only do area correction on fluxes + do i = 1, columns_on_task + cam_in%lhf(i) = -fldptr_lat(i) * med2mod_areacor(i) + cam_in%lwup(i) = -fldptr_lwup(i) * med2mod_areacor(i) + cam_in%asdir(i) = fldptr_avsdr(i) + cam_in%aldir(i) = fldptr_anidr(i) + cam_in%asdif(i) = fldptr_avsdf(i) + cam_in%aldif(i) = fldptr_anidf(i) + cam_in%ts(i) = fldptr_tsurf(i) + cam_in%sst(i) = fldptr_tocn(i) + cam_in%tref(i) = fldptr_tref(i) + cam_in%qref(i) = fldptr_qref(i) + cam_in%u10(i) = fldptr_u10(i) + cam_in%snowhland(i) = fldptr_snowhland(i) + cam_in%snowhice(i) = fldptr_snowhice(i) + cam_in%icefrac(i) = fldptr_ifrac(i) + cam_in%ocnfrac(i) = fldptr_ofrac(i) + cam_in%landfrac(i) = fldptr_lfrac(i) end do ! Optional fields @@ -490,104 +604,76 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) call state_getfldptr(importState, 'Sl_ram1', fldptr=fldptr1d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - if ( associated(cam_in(c)%ram1) ) then - do i = 1, get_ncols_p(c) - cam_in(c)%ram1(i) = fldptr1d(g) - g = g + 1 - end do - end if - end do + if ( associated(cam_in%ram1) ) then + do i = 1, columns_on_task + cam_in%ram1(i) = fldptr1d(i) + end do + end if end if call state_getfldptr(importState, 'Sl_fv', fldptr=fldptr1d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - if ( associated(cam_in(c)%fv) ) then - do i = 1,get_ncols_p(c) - cam_in(c)%fv(i) = fldptr1d(g) - g = g + 1 - end do - end if - end do + if ( associated(cam_in%fv) ) then + do i = 1, columns_on_task + cam_in%fv(i) = fldptr1d(i) + end do + end if end if ! For CARMA - soil water from land call state_getfldptr(importState, 'Sl_soilw', fldptr=fldptr1d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - if ( associated(cam_in(c)%soilw)) then - do i = 1,get_ncols_p(c) - cam_in(c)%soilw(i) = fldptr1d(g) - g = g+1 - end do - end if - end do + if ( associated(cam_in%soilw)) then + do i = 1, columns_on_task + cam_in%soilw(i) = fldptr1d(i) + end do + end if end if ! dry deposition fluxes from land call state_getfldptr(importState, 'Fall_flxdst', fldptr2d=fldptr2d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - if ( associated(cam_in(c)%dstflx) ) then - do i = 1,get_ncols_p(c) - do n = 1, size(fldptr2d, dim=1) - cam_in(c)%dstflx(i,n) = fldptr2d(n,g) - end do - g = g + 1 + if ( associated(cam_in%dstflx) ) then + do i = 1, columns_on_task + do n = 1, size(fldptr2d, dim=1) + cam_in%dstflx(i,n) = fldptr2d(n,i) * med2mod_areacor(i) end do - end if - end do + end do + end if end if ! MEGAN VOC emis fluxes from land call state_getfldptr(importState, 'Fall_voc', fldptr2d=fldptr2d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c=begchunk,endchunk - if ( associated(cam_in(c)%meganflx) ) then - do i = 1,get_ncols_p(c) - do n = 1, size(fldptr2d, dim=1) - cam_in(c)%meganflx(i,n) = fldptr2d(n,g) - end do - g = g + 1 + if ( associated(cam_in%meganflx) ) then + do i = 1, columns_on_task + do n = 1, size(fldptr2d, dim=1) + cam_in%meganflx(i,n) = fldptr2d(n,i) * med2mod_areacor(i) end do - end if - end do + end do + end if end if ! fire emission fluxes from land call state_getfldptr(importState, 'Fall_fire', fldptr2d=fldptr2d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - if ( associated(cam_in(c)%fireflx) .and. associated(cam_in(c)%fireztop) ) then - do i = 1,get_ncols_p(c) - do n = 1, size(fldptr2d, dim=1) - cam_in(c)%fireflx(i,n) = fldptr2d(n,g) - end do - g = g + 1 + if ( associated(cam_in%fireflx) .and. associated(cam_in%fireztop) ) then + do i = 1, columns_on_task + do n = 1, size(fldptr2d, dim=1) + cam_in%fireflx(i,n) = fldptr2d(n,i) * med2mod_areacor(i) end do - end if - end do + end do + end if end if call state_getfldptr(importState, 'Sl_fztop', fldptr=fldptr1d, exists=exists, rc=rc) if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%fireztop(i) = fldptr1d(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%fireztop(i) = fldptr1d(i) end do end if @@ -595,13 +681,9 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) call state_getfldptr(importState, 'Sl_ddvel', fldptr2d=fldptr2d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - do n = 1, size(fldptr2d, dim=1) - cam_in(c)%depvel(i,n) = fldptr2d(n,g) - end do - g = g + 1 + do i = 1, columns_on_task + do n = 1, size(fldptr2d, dim=1) + cam_in%depvel(i,n) = fldptr2d(n,i) end do end do end if @@ -610,34 +692,38 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) call state_getfldptr(importState, 'So_ustar', fldptr=fldptr1d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%ustar(i) = fldptr1d(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%ustar(i) = fldptr1d(i) end do end if call state_getfldptr(importState, 'So_re', fldptr=fldptr1d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%re(i)= fldptr1d(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%re(i)= fldptr1d(i) end do end if call state_getfldptr(importState, 'So_ssq', fldptr=fldptr1d, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%ssq(i) = fldptr1d(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%ssq(i) = fldptr1d(i) + end do + end if + + call state_getfldptr(importState, 'So_ugustOut', fldptr=fldptr1d, exists=exists, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (exists) then + do i = 1, columns_on_task + cam_in%ugustOut(i) = fldptr1d(i) + end do + end if + + call state_getfldptr(importState, 'So_u10withGust', fldptr=fldptr1d, exists=exists, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (exists) then + do i = 1, columns_on_task + cam_in%u10withGusts(i) = fldptr1d(i) end do end if @@ -645,23 +731,15 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) call state_getfldptr(importState, 'Fall_fco2_lnd', fldptr=fldptr1d, exists=exists_fco2_lnd, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists_fco2_lnd) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%fco2_lnd(i) = -fldptr1d(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%fco2_lnd(i) = -fldptr1d(i) * med2mod_areacor(i) end do end if call state_getfldptr(importState, 'Faoo_fco2_ocn', fldptr=fldptr1d, exists=exists_fco2_ocn, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists_fco2_ocn) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%fco2_ocn(i) = -fldptr1d(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%fco2_ocn(i) = -fldptr1d(i) * med2mod_areacor(i) end do else ! Consistency check @@ -671,12 +749,8 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) end if call state_getfldptr(importState, 'Faoo_dms_ocn', fldptr=fldptr1d, exists=exists, rc=rc) if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - cam_in(c)%fdms(i) = -fldptr1d(g) - g = g + 1 - end do + do i = 1, columns_on_task + cam_in%fdms(i) = -fldptr1d(i) * med2mod_areacor(i) end do end if @@ -701,36 +775,35 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) ! from lnd : through coupler or zero ! all co2 fluxes in unit kgCO2/m2/s - do c=begchunk,endchunk - do i=1, get_ncols_p(c) + do i=1, columns_on_task - ! co2 flux from ocn - if (exists_fco2_ocn) then - cam_in(c)%cflx(i,c_i(1)) = cam_in(c)%fco2_ocn(i) - else if (co2_readFlux_ocn) then - ! convert from molesCO2/m2/s to kgCO2/m2/s - cam_in(c)%cflx(i,c_i(1)) = & - -data_flux_ocn%co2flx(i,c)*(1._r8- cam_in(c)%landfrac(i))*mwco2*1.0e-3_r8 + ! co2 flux from ocn + if (exists_fco2_ocn) then + cam_in%cflx(i,c_i(1)) = cam_in%fco2_ocn(i) + else if (co2_readFlux_ocn) then + ! convert from molesCO2/m2/s to kgCO2/m2/s + cam_in%cflx(i,c_i(1)) = & + -data_flux_ocn%co2flx(i,c)*(1._r8- cam_in%landfrac(i))*mwco2*1.0e-3_r8 else - cam_in(c)%cflx(i,c_i(1)) = 0._r8 + cam_in%cflx(i,c_i(1)) = 0._r8 end if ! co2 flux from fossil fuel if (co2_readFlux_fuel) then - cam_in(c)%cflx(i,c_i(2)) = data_flux_fuel%co2flx(i,c) + cam_in%cflx(i,c_i(2)) = data_flux_fuel%co2flx(i) else - cam_in(c)%cflx(i,c_i(2)) = 0._r8 + cam_in%cflx(i,c_i(2)) = 0._r8 end if ! co2 flux from land (cpl already multiplies flux by land fraction) if (exists_fco2_lnd) then - cam_in(c)%cflx(i,c_i(3)) = cam_in(c)%fco2_lnd(i) + cam_in%cflx(i,c_i(3)) = cam_in%fco2_lnd(i) else - cam_in(c)%cflx(i,c_i(3)) = 0._r8 + cam_in%cflx(i,c_i(3)) = 0._r8 end if ! merged co2 flux - cam_in(c)%cflx(i,c_i(4)) = cam_in(c)%cflx(i,c_i(1)) + cam_in(c)%cflx(i,c_i(2)) + cam_in(c)%cflx(i,c_i(3)) + cam_in%cflx(i,c_i(4)) = cam_in%cflx(i,c_i(1)) + cam_in%cflx(i,c_i(2)) + cam_in%cflx(i,c_i(3)) end do end do end if @@ -738,85 +811,52 @@ subroutine import_fields( gcomp, cam_in, restart_init, rc) ! if first step, determine longwave up flux from the surface temperature if (first_time) then if (is_first_step()) then - do c=begchunk, endchunk - do i=1, get_ncols_p(c) - cam_in(c)%lwup(i) = shr_const_stebol*(cam_in(c)%ts(i)**4) - end do + do i=1, columns_on_task + cam_in%lwup(i) = shr_const_stebol*(cam_in%ts(i)**4) end do end if first_time = .false. end if - !----------------------------------------------------------------- - ! Debug import - !----------------------------------------------------------------- - - if (debug_import > 0 .and. masterproc .and. get_nstep()<5) then - nstep = get_nstep() - g=1 - do c=begchunk, endchunk - do i=1, get_ncols_p(c) - write(iulog,F01)'import: nstep, g, Faxx_tauy = ',nstep,g,-cam_in(c)%wsy(i) - write(iulog,F01)'import: nstep, g, Faxx_taux = ',nstep,g,-cam_in(c)%wsx(i) - write(iulog,F01)'import: nstep, g, Faxx_shf = ',nstep,g,-cam_in(c)%shf(i) - write(iulog,F01)'import: nstep, g, Faxx_lhf = ',nstep,g,-cam_in(c)%lhf(i) - write(iulog,F01)'import: nstep, g, Faxx_evap = ',nstep,g,-cam_in(c)%cflx(i,1) - write(iulog,F01)'import: nstep, g, Faxa_lwup = ',nstep,g,-cam_in(c)%lwup(i) - write(iulog,F01)'import: nstep, g, Sx_asdir = ',nstep,g, cam_in(c)%asdir(i) - write(iulog,F01)'import: nstep, g, Sx_aldir = ',nstep,g, cam_in(c)%aldir(i) - write(iulog,F01)'import: nstep, g, Sx_asdif = ',nstep,g, cam_in(c)%asdif(i) - write(iulog,F01)'import: nstep, g, Sx_aldif = ',nstep,g, cam_in(c)%aldif(i) - write(iulog,F01)'import: nstep, g, Sx_t = ',nstep,g, cam_in(c)%ts(i) - write(iulog,F01)'import: nstep, g, So_t = ',nstep,g, cam_in(c)%sst(i) - write(iulog,F01)'import: nstep, g, Sl_snowh = ',nstep,g, cam_in(c)%snowhland(i) - write(iulog,F01)'import: nstep, g, Si_snowh = ',nstep,g, cam_in(c)%snowhice(i) - write(iulog,F01)'import: nstep, g, Si_ifrac = ',nstep,g, cam_in(c)%icefrac(i) - write(iulog,F01)'import: nstep, g, So_ofrac = ',nstep,g, cam_in(c)%ocnfrac(i) - write(iulog,F01)'import: nstep, g, Sl_lfrac = ',nstep,g, cam_in(c)%landfrac(i) - write(iulog,F01)'import: nstep, g, Sx_tref = ',nstep,g, cam_in(c)%tref(i) - write(iulog,F01)'import: nstep, g, Sx_qref = ',nstep,g, cam_in(c)%qref(i) - write(iulog,F01)'import: nstep, g, Sx_qu10 = ',nstep,g, cam_in(c)%u10(i) - g = g + 1 - end do - end do - end if - !Remove once the "cam_in" object has been fully implemented. -JN #endif - if (dbug_flag > 10) call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) - end subroutine import_fields !=============================================================================== - subroutine export_fields( gcomp, cam_out, rc) + subroutine export_fields( gcomp, model_mesh, model_clock, cam_out, rc) ! ----------------------------------------------------- ! Set field pointers in export set - ! Copy from chunk array data structure into state fldptr + ! Copy from CAM-SIMA array data structure into state fldptr ! ----------------------------------------------------- - use camsrfexch , only : cam_out_t - use physics_grid , only : columns_on_task - use time_manager , only : is_first_step, get_nstep - use spmd_utils , only : masterproc + use ESMF , only : ESMF_Clock + use nuopc_shr_methods , only : chkerr + use srf_field_check , only : active_Faxa_nhx, active_Faxa_noy + use camsrfexch , only : cam_out_t + use time_manager , only : is_first_step, get_nstep + use physics_grid , only : columns_on_task + use atm_stream_ndep , only : stream_ndep_init, stream_ndep_interp + use atm_stream_ndep , only : stream_ndep_is_initialized !------------------------------- ! Pack the export state !------------------------------- ! input/output variables - type(ESMF_GridComp) :: gcomp - type(cam_out_t) , intent(in) :: cam_out - integer , intent(out) :: rc + type(ESMF_GridComp) :: gcomp + type(ESMF_Mesh) , intent(in) :: model_mesh + type(ESMF_Clock), intent(in) :: model_clock + type(cam_out_t) , intent(inout) :: cam_out + integer , intent(out) :: rc ! local variables type(ESMF_State) :: exportState - integer :: i,m,c,n,g ! indices - integer :: ncols ! Number of columns - integer :: nstep + integer :: i ! index variable logical :: exists + real(r8) :: scale_ndep ! 2d pointers real(r8), pointer :: fldptr_ndep(:,:) real(r8), pointer :: fldptr_bcph(:,:) , fldptr_ocph(:,:) @@ -833,6 +873,8 @@ subroutine export_fields( gcomp, cam_out, rc) real(r8), pointer :: fldptr_shum(:) , fldptr_dens(:) real(r8), pointer :: fldptr_ptem(:) , fldptr_pslv(:) real(r8), pointer :: fldptr_co2prog(:) , fldptr_co2diag(:) + real(r8), pointer :: fldptr_ozone(:) + real(r8), pointer :: fldptr_lght(:) character(len=*), parameter :: subname='(atm_import_export:export_fields)' !--------------------------------------------------------------------------- @@ -866,25 +908,21 @@ subroutine export_fields( gcomp, cam_out, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getfldptr(exportState, 'Sa_pslv', fldptr=fldptr_pslv, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - fldptr_topo(g) = cam_out(c)%topo(i) - fldptr_zbot(g) = cam_out(c)%zbot(i) - fldptr_ubot(g) = cam_out(c)%ubot(i) - fldptr_vbot(g) = cam_out(c)%vbot(i) - fldptr_pbot(g) = cam_out(c)%pbot(i) - fldptr_tbot(g) = cam_out(c)%tbot(i) - fldptr_shum(g) = cam_out(c)%qbot(i,1) - fldptr_dens(g) = cam_out(c)%rho(i) - fldptr_ptem(g) = cam_out(c)%thbot(i) - fldptr_pslv(g) = cam_out(c)%psl(i) - g = g + 1 - end do + do i = 1, columns_on_task + fldptr_topo(i) = cam_out%topo(i) + fldptr_zbot(i) = cam_out%zbot(i) + fldptr_ubot(i) = cam_out%ubot(i) + fldptr_vbot(i) = cam_out%vbot(i) + fldptr_pbot(i) = cam_out%pbot(i) + fldptr_tbot(i) = cam_out%tbot(i) + fldptr_shum(i) = cam_out%qbot(i,1) + fldptr_dens(i) = cam_out%rho(i) + fldptr_ptem(i) = cam_out%thbot(i) + fldptr_pslv(i) = cam_out%psl(i) end do ! required export flux variables - call state_getfldptr(exportState, 'Faxa_swnet', fldptr=fldptr_swnet, rc=rc) + call state_getfldptr(exportState, 'Faxa_swnet', fldptr=fldptr_swnet, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getfldptr(exportState, 'Faxa_lwdn' , fldptr=fldptr_lwdn , rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -904,21 +942,17 @@ subroutine export_fields( gcomp, cam_out, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_getfldptr(exportState, 'Faxa_swvdf', fldptr=fldptr_solsd, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - fldptr_lwdn(g) = cam_out(c)%flwds(i) - fldptr_swnet(g) = cam_out(c)%netsw(i) - fldptr_snowc(g) = cam_out(c)%precsc(i)*1000._r8 - fldptr_snowl(g) = cam_out(c)%precsl(i)*1000._r8 - fldptr_rainc(g) = (cam_out(c)%precc(i)-cam_out(c)%precsc(i))*1000._r8 - fldptr_rainl(g) = (cam_out(c)%precl(i)-cam_out(c)%precsl(i))*1000._r8 - fldptr_soll(g) = cam_out(c)%soll(i) - fldptr_sols(g) = cam_out(c)%sols(i) - fldptr_solld(g) = cam_out(c)%solld(i) - fldptr_solsd(g) = cam_out(c)%solsd(i) - g = g + 1 - end do + do i = 1, columns_on_task + fldptr_lwdn(i) = cam_out%flwds(i) * mod2med_areacor(i) + fldptr_swnet(i) = cam_out%netsw(i) * mod2med_areacor(i) + fldptr_snowc(i) = cam_out%precsc(i)*1000._r8 * mod2med_areacor(i) + fldptr_snowl(i) = cam_out%precsl(i)*1000._r8 * mod2med_areacor(i) + fldptr_rainc(i) = (cam_out%precc(i) - cam_out(c)%precsc(i))*1000._r8 * mod2med_areacor(i) + fldptr_rainl(i) = (cam_out%precl(i) - cam_out(c)%precsl(i))*1000._r8 * mod2med_areacor(i) + fldptr_soll(i) = cam_out%soll(i) * mod2med_areacor(i) + fldptr_sols(i) = cam_out%sols(i) * mod2med_areacor(i) + fldptr_solld(i) = cam_out%solld(i) * mod2med_areacor(i) + fldptr_solsd(i) = cam_out%solsd(i) * mod2med_areacor(i) end do ! aerosol deposition fluxes @@ -932,114 +966,79 @@ subroutine export_fields( gcomp, cam_out, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! (1) => bcphidry, (2) => bcphodry, (3) => bcphiwet ! (1) => ocphidry, (2) => ocphodry, (3) => ocphiwet - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - fldptr_bcph(1,g) = cam_out(c)%bcphidry(i) - fldptr_bcph(2,g) = cam_out(c)%bcphodry(i) - fldptr_bcph(3,g) = cam_out(c)%bcphiwet(i) - fldptr_ocph(1,g) = cam_out(c)%ocphidry(i) - fldptr_ocph(2,g) = cam_out(c)%ocphodry(i) - fldptr_ocph(3,g) = cam_out(c)%ocphiwet(i) - fldptr_dstdry(1,g) = cam_out(c)%dstdry1(i) - fldptr_dstdry(2,g) = cam_out(c)%dstdry2(i) - fldptr_dstdry(3,g) = cam_out(c)%dstdry3(i) - fldptr_dstdry(4,g) = cam_out(c)%dstdry4(i) - fldptr_dstwet(1,g) = cam_out(c)%dstwet1(i) - fldptr_dstwet(2,g) = cam_out(c)%dstwet2(i) - fldptr_dstwet(3,g) = cam_out(c)%dstwet3(i) - fldptr_dstwet(4,g) = cam_out(c)%dstwet4(i) - g = g + 1 - end do + do i = 1, columns_on_task + fldptr_bcph(1,i) = cam_out%bcphidry(i) * mod2med_areacor(i) + fldptr_bcph(2,i) = cam_out%bcphodry(i) * mod2med_areacor(i) + fldptr_bcph(3,i) = cam_out%bcphiwet(i) * mod2med_areacor(i) + fldptr_ocph(1,i) = cam_out%ocphidry(i) * mod2med_areacor(i) + fldptr_ocph(2,i) = cam_out%ocphodry(i) * mod2med_areacor(i) + fldptr_ocph(3,i) = cam_out%ocphiwet(i) * mod2med_areacor(i) + fldptr_dstdry(1,i) = cam_out%dstdry1(i) * mod2med_areacor(i) + fldptr_dstdry(2,i) = cam_out%dstdry2(i) * mod2med_areacor(i) + fldptr_dstdry(3,i) = cam_out%dstdry3(i) * mod2med_areacor(i) + fldptr_dstdry(4,i) = cam_out%dstdry4(i) * mod2med_areacor(i) + fldptr_dstwet(1,i) = cam_out%dstwet1(i) * mod2med_areacor(i) + fldptr_dstwet(2,i) = cam_out%dstwet2(i) * mod2med_areacor(i) + fldptr_dstwet(3,i) = cam_out%dstwet3(i) * mod2med_areacor(i) + fldptr_dstwet(4,i) = cam_out%dstwet4(i) * mod2med_areacor(i) end do - call state_getfldptr(exportState, 'Sa_co2prog', fldptr=fldptr_co2prog, exists=exists, rc=rc) + call state_getfldptr(exportState, 'Sa_o3', fldptr=fldptr_ozone, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - fldptr_co2prog(g) = cam_out(c)%co2prog(i) ! atm prognostic co2 - g = g + 1 - end do + do i = 1, columns_on_task + fldptr_ozone(i) = cam_out%ozone(i) ! atm ozone end do end if - call state_getfldptr(exportState, 'Sa_co2diag', fldptr=fldptr_co2diag, exists=exists, rc=rc) + call state_getfldptr(exportState, 'Sa_lightning', fldptr=fldptr_lght, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - fldptr_co2diag(g) = cam_out(c)%co2diag(i) ! atm diagnostic co2 - g = g + 1 - end do + do i = 1, columns_on_task + fldptr_lght(i) = cam_out%lightning_flash_freq(i) ! cloud-to-ground lightning flash frequency (/min) end do end if - call state_getfldptr(exportState, 'Faxa_ndep', fldptr2d=fldptr_ndep, exists=exists, rc=rc) + call state_getfldptr(exportState, 'Sa_co2prog', fldptr=fldptr_co2prog, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - ! (1) => nhx, (2) => noy - g = 1 - do c = begchunk,endchunk - do i = 1,get_ncols_p(c) - fldptr_ndep(1,g) = cam_out(c)%nhx_nitrogen_flx(i) - fldptr_ndep(2,g) = cam_out(c)%noy_nitrogen_flx(i) - g = g + 1 - end do + do i = 1, columns_on_task + fldptr_co2prog(i) = cam_out%co2prog(i) ! atm prognostic co2 end do end if - !----------------------------------------------------------------- - ! Debug export - !----------------------------------------------------------------- - - if (debug_export > 0 .and. masterproc .and. get_nstep()<5) then - nstep = get_nstep() - g=1 - do c=begchunk, endchunk - do i=1, get_ncols_p(c) - write(iulog,F01)'export: nstep, g, Sa_z = ',nstep,g,cam_out(c)%zbot(i) - write(iulog,F01)'export: nstep, g, Sa_topo = ',nstep,g,cam_out(c)%topo(i) - write(iulog,F01)'export: nstep, g, Sa_u = ',nstep,g,cam_out(c)%ubot(i) - write(iulog,F01)'export: nstep, g, Sa_v = ',nstep,g,cam_out(c)%vbot(i) - write(iulog,F01)'export: nstep, g, Sa_tbot = ',nstep,g,cam_out(c)%tbot(i) - write(iulog,F01)'export: nstep, g, Sa_ptem = ',nstep,g,cam_out(c)%thbot(i) - write(iulog,F01)'export: nstep, g, Sa_pbot = ',nstep,g,cam_out(c)%pbot(i) - write(iulog,F01)'export: nstep, g, Sa_shum = ',nstep,g,cam_out(c)%qbot(i,1) - write(iulog,F01)'export: nstep, g, Sa_dens = ',nstep,g,cam_out(c)%rho(i) - write(iulog,F01)'export: nstep, g, Faxa_swnet = ',nstep,g,cam_out(c)%netsw(i) - write(iulog,F01)'export: nstep, g, Faxa_lwdn = ',nstep,g,cam_out(c)%flwds(i) - write(iulog,F01)'export: nstep, g, Faxa_rainc = ',nstep,g,(cam_out(c)%precc(i)-cam_out(c)%precsc(i))*1000._r8 - write(iulog,F01)'export: nstep, g, Faxa_rainl = ',nstep,g,(cam_out(c)%precl(i)-cam_out(c)%precsl(i))*1000._r8 - write(iulog,F01)'export: nstep, g, Faxa_snowc = ',nstep,g,cam_out(c)%precsc(i)*1000._r8 - write(iulog,F01)'export: nstep, g, Faxa_snowl = ',nstep,g,cam_out(c)%precsl(i)*1000._r8 - write(iulog,F01)'export: nstep, g, Faxa_swndr = ',nstep,g,cam_out(c)%soll(i) - write(iulog,F01)'export: nstep, g, Faxa_swvdr = ',nstep,g,cam_out(c)%sols(i) - write(iulog,F01)'export: nstep, g, Faxa_swndf = ',nstep,g,cam_out(c)%solld(i) - write(iulog,F01)'export: nstep, g, Faxa_swvdf = ',nstep,g,cam_out(c)%solsd(i) - write(iulog,F01)'export: nstep, g, Faxa_bcphidry = ',nstep,g,cam_out(c)%bcphidry(i) - write(iulog,F01)'export: nstep, g, Faxa_bcphodry = ',nstep,g,cam_out(c)%bcphodry(i) - write(iulog,F01)'export: nstep, g, Faxa_bcphiwet = ',nstep,g,cam_out(c)%bcphiwet(i) - write(iulog,F01)'export: nstep, g, Faxa_ocphidry = ',nstep,g,cam_out(c)%ocphidry(i) - write(iulog,F01)'export: nstep, g, Faxa_ocphodry = ',nstep,g,cam_out(c)%ocphodry(i) - write(iulog,F01)'export: nstep, g, Faxa_ocphidry = ',nstep,g,cam_out(c)%ocphiwet(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet1 = ',nstep,g,cam_out(c)%dstwet1(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet1 = ',nstep,g,cam_out(c)%dstdry1(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet2 = ',nstep,g,cam_out(c)%dstwet2(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet2 = ',nstep,g,cam_out(c)%dstdry2(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet3 = ',nstep,g,cam_out(c)%dstwet3(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet3 = ',nstep,g,cam_out(c)%dstdry3(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet4 = ',nstep,g,cam_out(c)%dstwet4(i) - write(iulog,F01)'export: nstep, g, Faxa_dstwet4 = ',nstep,g,cam_out(c)%dstdry4(i) - write(iulog,F01)'export: nstep, g, Sa_co2prog = ',nstep,g,cam_out(c)%co2prog(i) - write(iulog,F01)'export: nstep, g, Sa_co2diag = ',nstep,g,cam_out(c)%co2diag(i) - g = g + 1 - end do + call state_getfldptr(exportState, 'Sa_co2diag', fldptr=fldptr_co2diag, exists=exists, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (exists) then + do i = 1, columns_on_task + fldptr_co2diag(i) = cam_out%co2diag(i) ! atm diagnostic co2 end do end if + ! If ndep fields are not computed in cam and must be obtained from the ndep input stream + call state_getfldptr(exportState, 'Faxa_ndep', fldptr2d=fldptr_ndep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (.not. active_Faxa_nhx .and. .not. active_Faxa_noy) then + if (.not. stream_ndep_is_initialized) then + call stream_ndep_init(model_mesh, model_clock, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + stream_ndep_is_initialized = .true. + end if + call stream_ndep_interp(cam_out, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! NDEP read from forcing is expected to be in units of gN/m2/sec - but the mediator + ! expects units of kgN/m2/sec + scale_ndep = .001_r8 + else + ! If waccm computes ndep, then its in units of kgN/m2/s - and the mediator expects + ! units of kgN/m2/sec, so the following conversion needs to happen + scale_ndep = 1._r8 + end if + do i = 1, columns_on_task + fldptr_ndep(1,i) = cam_out(c)%nhx_nitrogen_flx(i) * scale_ndep * mod2med_areacor(i) + fldptr_ndep(2,i) = cam_out(c)%noy_nitrogen_flx(i) * scale_ndep * mod2med_areacor(i) + end do + !Remove once the "cam_in" object has been fully implemented. -JN #endif @@ -1049,6 +1048,9 @@ end subroutine export_fields subroutine fldlist_add(num, fldlist, stdname, ungridded_lbound, ungridded_ubound) + ! use statements + use ESMF , only : ESMF_LOGMSG_ERROR + ! input/otuput variables integer , intent(inout) :: num type(fldlist_type) , intent(inout) :: fldlist(:) @@ -1081,14 +1083,18 @@ end subroutine fldlist_add subroutine fldlist_realize(state, fldList, numflds, flds_scalar_name, flds_scalar_num, mesh, tag, rc) - use NUOPC , only : NUOPC_IsConnected, NUOPC_Realize - use ESMF , only : ESMF_MeshLoc_Element, ESMF_FieldCreate, ESMF_TYPEKIND_R8 - use ESMF , only : ESMF_MAXSTR, ESMF_Field, ESMF_State, ESMF_Mesh, ESMF_StateRemove - use ESMF , only : ESMF_LogFoundError, ESMF_LOGMSG_INFO, ESMF_SUCCESS - use ESMF , only : ESMF_LogWrite, ESMF_LOGMSG_ERROR, ESMF_LOGERR_PASSTHRU + use NUOPC , only : NUOPC_IsConnected, NUOPC_Realize + use ESMF , only : ESMF_MeshLoc_Element, ESMF_FieldCreate, ESMF_TYPEKIND_R8 + use ESMF , only : ESMF_Field, ESMF_State, ESMF_Mesh, ESMF_StateRemove + use ESMF , only : ESMF_LogFoundError, ESMF_LOGMSG_INFO, ESMF_SUCCESS + use ESMF , only : ESMF_LogWrite, ESMF_LOGERR_PASSTHRU + use nuopc_shr_methods , only : chkerr + use spmd_utils , only : masterproc + use cam_logfile , only : iulog + ! input/output variables type(ESMF_State) , intent(inout) :: state - type(fldlist_type) , intent(in) :: fldList(:) + type(fldlist_type) , intent(in) :: fldList(:) integer , intent(in) :: numflds character(len=*) , intent(in) :: flds_scalar_name integer , intent(in) :: flds_scalar_num @@ -1110,8 +1116,9 @@ subroutine fldlist_realize(state, fldList, numflds, flds_scalar_name, flds_scala stdname = fldList(n)%stdname if (NUOPC_IsConnected(state, fieldName=stdname)) then if (stdname == trim(flds_scalar_name)) then - call ESMF_LogWrite(trim(subname)//trim(tag)//" Field = "//trim(stdname)//" is connected on root pe", & - ESMF_LOGMSG_INFO) + if (masterproc) then + write(iulog,'(a)') trim(subname)//trim(tag)//" field = "//trim(stdname)//" is connected on root pe" + end if ! Create the scalar field call SetScalarField(field, flds_scalar_name, flds_scalar_num, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return @@ -1123,14 +1130,17 @@ subroutine fldlist_realize(state, fldList, numflds, flds_scalar_name, flds_scala ungriddedUbound=(/fldlist(n)%ungridded_ubound/), & gridToFieldMap=(/2/), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - write(msg,*) trim(subname)// trim(tag)//" Field = "//trim(stdname)// " is connected using mesh ", & - "with lbound ", fldlist(n)%ungridded_lbound,' and with ubound ',fldlist(n)%ungridded_ubound - call ESMF_LogWrite(msg, ESMF_LOGMSG_INFO) + if (masterproc) then + write(iulog,'(a,i8,a,i8)') trim(subname)// trim(tag)//" Field = "//trim(stdname)// & + " is connected using mesh with lbound ", fldlist(n)%ungridded_lbound,& + " and with ubound ",fldlist(n)%ungridded_ubound + end if else field = ESMF_FieldCreate(mesh, ESMF_TYPEKIND_R8, name=stdname, meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return - write(msg,*) trim(subname)// trim(tag)//" Field = "//trim(stdname)// " is connected using mesh " - call ESMF_LogWrite(msg, ESMF_LOGMSG_INFO) + if (masterproc) then + write(iulog,'(a)') trim(subname)// trim(tag)//" Field = "//trim(stdname)// " is connected using mesh " + end if end if endif @@ -1139,8 +1149,9 @@ subroutine fldlist_realize(state, fldList, numflds, flds_scalar_name, flds_scala if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return else if (stdname /= trim(flds_scalar_name)) then - call ESMF_LogWrite(subname // trim(tag) // " Field = "// trim(stdname) // " is not connected.", & - ESMF_LOGMSG_INFO) + if (masterproc) then + write(iulog,'(a)')trim(subname)//trim(tag)//" Field = "//trim(stdname)//" is not connected" + end if call ESMF_StateRemove(state, (/stdname/), rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=u_FILE_u)) return end if @@ -1188,16 +1199,17 @@ end subroutine SetScalarField end subroutine fldlist_realize !=============================================================================== - subroutine state_getfldptr(State, fldname, fldptr, fldptr2d, exists, rc) ! ---------------------------------------------- ! Get pointer to a state field ! ---------------------------------------------- - use ESMF , only : ESMF_State, ESMF_Field, ESMF_Mesh, ESMF_FieldStatus_Flag - use ESMF , only : ESMF_StateGet, ESMF_FieldGet, ESMF_MeshGet - use ESMF , only : ESMF_FIELDSTATUS_COMPLETE, ESMF_FAILURE + use ESMF , only : ESMF_State, ESMF_Field, ESMF_Mesh, ESMF_FieldStatus_Flag + use ESMF , only : ESMF_StateGet, ESMF_FieldGet, ESMF_MeshGet + use ESMF , only : ESMF_FIELDSTATUS_COMPLETE, ESMF_FAILURE + use ESMF , only : ESMF_STATEITEM_NOTFOUND, ESMF_StateItem_Flag + use nuopc_shr_methods , only : chkerr ! input/output variables type(ESMF_State) , intent(in) :: State @@ -1213,56 +1225,27 @@ subroutine state_getfldptr(State, fldname, fldptr, fldptr2d, exists, rc) type(ESMF_Field) :: lfield type(ESMF_Mesh) :: lmesh integer :: nnodes, nelements + logical :: lexists character(len=*), parameter :: subname='(atm_import_export:state_getfldptr)' ! ---------------------------------------------- rc = ESMF_SUCCESS - if (dbug_flag > 10) then - call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO) - endif + lexists = .true. ! Determine if field with name fldname exists in state - call ESMF_StateGet(state, trim(fldname), itemFlag, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (present(exists)) then - ! if field exists then create output array - else do nothing - if (itemflag == ESMF_STATEITEM_NOTFOUND) then - exists = .false. - RETURN - else - exists = .true. - end if - else + call ESMF_StateGet(state, trim(fldname), itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return if (itemflag == ESMF_STATEITEM_NOTFOUND) then - call shr_sys_abort('variable '//trim(fldname)//' must be present ') + lexists = .false. end if + exists = lexists end if - call ESMF_StateGet(State, itemName=trim(fldname), field=lfield, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - call ESMF_FieldGet(lfield, status=status, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - if (status /= ESMF_FIELDSTATUS_COMPLETE) then - call ESMF_LogWrite(trim(subname)//": ERROR data not allocated ", ESMF_LOGMSG_INFO, rc=rc) - rc = ESMF_FAILURE - return - else - call ESMF_FieldGet(lfield, mesh=lmesh, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - call ESMF_MeshGet(lmesh, numOwnedNodes=nnodes, numOwnedElements=nelements, rc=rc) + if (lexists) then + call ESMF_StateGet(State, itemName=trim(fldname), field=lfield, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - - if (nnodes == 0 .and. nelements == 0) then - call ESMF_LogWrite(trim(subname)//": no local nodes or elements ", ESMF_LOGMSG_INFO) - rc = ESMF_FAILURE - return - end if - if (present(fldptr)) then call ESMF_FieldGet(lfield, farrayPtr=fldptr, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -1270,11 +1253,7 @@ subroutine state_getfldptr(State, fldname, fldptr, fldptr2d, exists, rc) call ESMF_FieldGet(lfield, farrayPtr=fldptr2d, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if - endif ! status - - if (dbug_flag > 10) then - call ESMF_LogWrite(trim(subname)//": done", ESMF_LOGMSG_INFO) - endif + end if end subroutine state_getfldptr diff --git a/src/cpl/nuopc/atm_stream_ndep.F90 b/src/cpl/nuopc/atm_stream_ndep.F90 new file mode 100644 index 00000000..dc8616ad --- /dev/null +++ b/src/cpl/nuopc/atm_stream_ndep.F90 @@ -0,0 +1,262 @@ +module atm_stream_ndep + + !----------------------------------------------------------------------- + ! Contains methods for reading in nitrogen deposition data file + ! Also includes functions for dynamic ndep file handling and + ! interpolation. + !----------------------------------------------------------------------- + ! + use ESMF , only : ESMF_Clock + use dshr_strdata_mod , only : shr_strdata_type + use shr_kind_mod , only : CS => shr_kind_cs + + implicit none + private + + public :: stream_ndep_init ! position datasets for dynamic ndep + public :: stream_ndep_interp ! interpolates between two years of ndep file data + + private :: stream_ndep_check_units ! Check the units and make sure they can be used + + type(shr_strdata_type) :: sdat_ndep ! input data stream + logical, public :: stream_ndep_is_initialized = .false. + character(len=CS) :: stream_varlist_ndep(2) + type(ESMF_Clock) :: model_clock + + character(len=*), parameter :: sourcefile = & + __FILE__ + +!============================================================================== +contains +!============================================================================== + + subroutine stream_ndep_init(model_mesh, model_clock, rc) + ! + ! Initialize data stream information. + + ! Uses: + use ESMF , only: ESMF_Mesh + use ESMF , only: ESMF_SUCCESS, ESMF_LOGERR_PASSTHRU, ESMF_END_ABORT + use ESMF , only: ESMF_Finalize, ESMF_LogFoundError + use cam_instance , only: inst_suffix + use shr_nl_mod , only: shr_nl_find_group_name + use shr_kind_mod , only: CL => shr_kind_cl + use shr_kind_mod , only: r8 => shr_kind_r8 + use shr_log_mod , only: errMsg => shr_log_errMsg + use dshr_strdata_mod , only: shr_strdata_init_from_inline + use mpi , only: mpi_character, mpi_integer + use spmd_utils , only: mpicom, masterproc, iam + use cam_logfile , only: iulog + use cam_abortutils , only: endrun + + ! input/output variables + type(ESMF_CLock), intent(in) :: model_clock + type(ESMF_Mesh) , intent(in) :: model_mesh + integer , intent(out) :: rc + + ! local variables + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + character(len=CL) :: stream_ndep_data_filename + character(len=CL) :: stream_ndep_mesh_filename + character(len=CL) :: filein ! atm namelist file + integer :: stream_ndep_year_first ! first year in stream to use + integer :: stream_ndep_year_last ! last year in stream to use + integer :: stream_ndep_year_align ! align stream_year_firstndep with + integer :: ierr + character(*), parameter :: subName = "('stream_ndep_init')" + !----------------------------------------------------------------------- + + namelist /ndep_stream_nl/ & + stream_ndep_data_filename, & + stream_ndep_mesh_filename, & + stream_ndep_year_first, & + stream_ndep_year_last, & + stream_ndep_year_align + + rc = ESMF_SUCCESS + + ! Default values for namelist + stream_ndep_data_filename = ' ' + stream_ndep_mesh_filename = ' ' + stream_ndep_year_first = 1 ! first year in stream to use + stream_ndep_year_last = 1 ! last year in stream to use + stream_ndep_year_align = 1 ! align stream_ndep_year_first with this model year + + ! For now variable list in stream data file is hard-wired + stream_varlist_ndep = (/'NDEP_NHx_month', 'NDEP_NOy_month'/) + + ! Read ndep_stream namelist + if (masterproc) then + filein = "atm_in" // trim(inst_suffix) + open( newunit=nu_nml, file=trim(filein), status='old', iostat=nml_error ) + if (nml_error /= 0) then + call endrun(subName//': ERROR opening '//trim(filein)//errMsg(sourcefile, __LINE__)) + end if + call shr_nl_find_group_name(nu_nml, 'ndep_stream_nl', status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=ndep_stream_nl, iostat=nml_error) + if (nml_error /= 0) then + call endrun(' ERROR reading ndep_stream_nl namelist'//errMsg(sourcefile, __LINE__)) + end if + else + call endrun(' ERROR finding ndep_stream_nl namelist'//errMsg(sourcefile, __LINE__)) + end if + close(nu_nml) + endif + call mpi_bcast(stream_ndep_mesh_filename, len(stream_ndep_mesh_filename), mpi_character, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_mesh_filename") + call mpi_bcast(stream_ndep_data_filename, len(stream_ndep_data_filename), mpi_character, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_data_filename") + call mpi_bcast(stream_ndep_year_first, 1, mpi_integer, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_year_first") + call mpi_bcast(stream_ndep_year_last, 1, mpi_integer, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_year_last") + call mpi_bcast(stream_ndep_year_align, 1, mpi_integer, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_year_align") + + if (masterproc) then + write(iulog,'(a)' ) ' ' + write(iulog,'(a,i8)') 'stream ndep settings:' + write(iulog,'(a,a)' ) ' stream_ndep_data_filename = ',trim(stream_ndep_data_filename) + write(iulog,'(a,a)' ) ' stream_ndep_mesh_filename = ',trim(stream_ndep_mesh_filename) + write(iulog,'(a,a,a)') ' stream_varlist_ndep = ',trim(stream_varlist_ndep(1)), trim(stream_varlist_ndep(2)) + write(iulog,'(a,i8)') ' stream_ndep_year_first = ',stream_ndep_year_first + write(iulog,'(a,i8)') ' stream_ndep_year_last = ',stream_ndep_year_last + write(iulog,'(a,i8)') ' stream_ndep_year_align = ',stream_ndep_year_align + write(iulog,'(a)' ) ' ' + endif + + ! Read in units + call stream_ndep_check_units(stream_ndep_data_filename) + + ! Initialize the cdeps data type sdat_ndep + call shr_strdata_init_from_inline(sdat_ndep, & + my_task = iam, & + logunit = iulog, & + compname = 'ATM', & + model_clock = model_clock, & + model_mesh = model_mesh, & + stream_meshfile = trim(stream_ndep_mesh_filename), & + stream_filenames = (/trim(stream_ndep_data_filename)/), & + stream_yearFirst = stream_ndep_year_first, & + stream_yearLast = stream_ndep_year_last, & + stream_yearAlign = stream_ndep_year_align, & + stream_fldlistFile = stream_varlist_ndep, & + stream_fldListModel = stream_varlist_ndep, & + stream_lev_dimname = 'null', & + stream_mapalgo = 'bilinear', & + stream_offset = 0, & + stream_taxmode = 'cycle', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = 'linear', & + stream_name = 'Nitrogen deposition data ', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + end subroutine stream_ndep_init + + !================================================================ + subroutine stream_ndep_check_units( stream_fldFileName_ndep) + + !-------------------------------------------------------- + ! Check that units are correct on the file and if need any conversion + !-------------------------------------------------------- + + use cam_pio_utils , only : cam_pio_createfile, cam_pio_openfile, cam_pio_closefile, pio_subsystem + use pio , only : file_desc_t, io_desc_t, var_desc_t, pio_double, pio_def_dim + use pio , only : pio_bcast_error, pio_seterrorhandling, pio_inq_varid, pio_get_att + use pio , only : PIO_NOERR, PIO_NOWRITE + use shr_log_mod , only : errMsg => shr_log_errMsg + use cam_abortutils , only : endrun + + ! Arguments + character(len=*), intent(in) :: stream_fldFileName_ndep ! ndep filename + ! + ! Local variables + type(file_desc_t) :: File ! NetCDF filehandle for ndep file + type(var_desc_t) :: vardesc ! variable descriptor + integer :: ierr ! error status + integer :: err_handling ! temporary + character(len=CS) :: ndepunits! ndep units + !----------------------------------------------------------------------- + + call cam_pio_openfile( File, trim(stream_fldFileName_ndep), PIO_NOWRITE) + call pio_seterrorhandling(File, PIO_BCAST_ERROR, err_handling) + ierr = pio_inq_varid(File, stream_varlist_ndep(1), vardesc) + if (ierr /= PIO_NOERR) then + call endrun(' ERROR finding variable: '//trim(stream_varlist_ndep(1))//" in file: "// & + trim(stream_fldFileName_ndep)//errMsg(sourcefile, __LINE__)) + else + ierr = PIO_get_att(File, vardesc, "units", ndepunits) + end if + call pio_seterrorhandling(File, err_handling) + call cam_pio_closefile(File) + + ! Now check to make sure they are correct + if (.not. trim(ndepunits) == "g(N)/m2/s" )then + call endrun(' ERROR in units for nitrogen deposition equal to: '//trim(ndepunits)//" not units expected"// & + errMsg(sourcefile, __LINE__)) + end if + + end subroutine stream_ndep_check_units + + !================================================================ + subroutine stream_ndep_interp(cam_out, rc) + + use ESMF , only : ESMF_LOGERR_PASSTHRU, ESMF_END_ABORT + use ESMF , only : ESMF_Finalize, ESMF_LogFoundError + use dshr_methods_mod , only : dshr_fldbun_getfldptr + use dshr_strdata_mod , only : shr_strdata_advance + use shr_kind_mod , only : r8 => shr_kind_r8 + use camsrfexch , only : cam_out_t + use time_manager , only : get_curr_date + use physics_grid , only : columns_on_task + use cam_logfile , only : iulog + + ! input/output variables + type(cam_out_t) , intent(inout) :: cam_out + integer , intent(out) :: rc + + ! local variables + integer :: i + integer :: year ! year (0, ...) for nstep+1 + integer :: mon ! month (1, ..., 12) for nstep+1 + integer :: day ! day of month (1, ..., 31) for nstep+1 + integer :: sec ! seconds into current date for nstep+1 + integer :: mcdate ! Current model date (yyyymmdd) + real(r8), pointer :: dataptr1d_nhx(:) + real(r8), pointer :: dataptr1d_noy(:) + !----------------------------------------------------------------------- + + ! Advance sdat stream + call get_curr_date(year, mon, day, sec) + mcdate = year*10000 + mon*100 + day + call shr_strdata_advance(sdat_ndep, ymd=mcdate, tod=sec, logunit=iulog, istr='ndepdyn', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Get pointer for stream data that is time and spatially interpolated to model time and grid + call dshr_fldbun_getFldPtr(sdat_ndep%pstrm(1)%fldbun_model, stream_varlist_ndep(1), fldptr1=dataptr1d_nhx, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + call dshr_fldbun_getFldPtr(sdat_ndep%pstrm(1)%fldbun_model, stream_varlist_ndep(2), fldptr1=dataptr1d_noy, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + +!Un-comment once cam_out data structure has been populated -JN +#if 0 + do i = 1, columns_on_task + cam_out%nhx_nitrogen_flx(i) = dataptr1d_nhx(g) + cam_out%noy_nitrogen_flx(i) = dataptr1d_noy(g) + end do +#endif + + end subroutine stream_ndep_interp + +end module atm_stream_ndep diff --git a/src/data/physconst.meta b/src/data/physconst.meta index b3646d73..127dbe35 100644 --- a/src/data/physconst.meta +++ b/src/data/physconst.meta @@ -292,7 +292,7 @@ dimensions = () protected = True [ cappa ] - standard_name = ratio_of_dry_air_to_water_vapor_gas_constants + standard_name = ratio_of_dry_air_gas_constant_to_specific_heat_of_dry_air_at_constant_pressure units = 1 type = real | kind = kind_phys dimensions = () diff --git a/src/dynamics/se/dyn_grid.F90 b/src/dynamics/se/dyn_grid.F90 index a8bd51e3..51fdb2da 100644 --- a/src/dynamics/se/dyn_grid.F90 +++ b/src/dynamics/se/dyn_grid.F90 @@ -83,7 +83,6 @@ module dyn_grid public :: model_grid_init !!XXgoldyXX: v try to remove? -public :: get_horiz_grid_dim_d public :: dyn_grid_get_colndx ! get element block/column and MPI process indices !!XXgoldyXX: ^ try to remove? public :: dyn_grid_get_elem_coords ! get coords of a specified block element @@ -520,30 +519,6 @@ subroutine set_dyn_col_values() end subroutine set_dyn_col_values -!============================================================================== - -subroutine get_horiz_grid_dim_d(hdim1_d,hdim2_d) - - ! Returns declared horizontal dimensions of computational grid. - ! For non-lon/lat grids, declare grid to be one-dimensional, - ! i.e., (ngcols_d x 1) - - !------------------------------Arguments-------------------------------- - integer, intent(out) :: hdim1_d ! first horizontal dimension - integer, intent(out), optional :: hdim2_d ! second horizontal dimension - !----------------------------------------------------------------------- - - if (fv_nphys > 0) then - hdim1_d = fv_nphys*fv_nphys*nelem_d - else - hdim1_d = ngcols_d - end if - if (present(hdim2_d)) then - hdim2_d = 1 - end if - -end subroutine get_horiz_grid_dim_d - !========================================================================================= subroutine get_horiz_grid_int(nxy, clat_d_out, clon_d_out, area_d_out, & diff --git a/src/physics/utils/physics_grid.F90 b/src/physics/utils/physics_grid.F90 index de59b560..39fc0f99 100644 --- a/src/physics/utils/physics_grid.F90 +++ b/src/physics/utils/physics_grid.F90 @@ -56,7 +56,7 @@ module physics_grid ! dynamics field grid information ! hdim1_d and hdim2_d are dimensions of rectangular horizontal grid ! data structure, If 1D data structure, then hdim2_d == 1. - integer :: hdim1_d, hdim2_d + integer, protected, public :: hdim1_d, hdim2_d logical :: dycore_unstructured = .false. ! Dycore name and properties character(len=8), protected, public :: dycore_name = '' diff --git a/src/utils/cam_pio_utils.F90 b/src/utils/cam_pio_utils.F90 index 5421d9e2..ad7a796a 100644 --- a/src/utils/cam_pio_utils.F90 +++ b/src/utils/cam_pio_utils.F90 @@ -45,7 +45,7 @@ module cam_pio_utils integer :: pio_rearranger ! This variable should be private ? - type(iosystem_desc_t), pointer, public, protected :: pio_subsystem => null() + type(iosystem_desc_t), pointer, public :: pio_subsystem => null() ! Some private string length parameters integer, parameter :: errormsg_str_len = 128 diff --git a/test/run_tests.sh b/test/run_unit_tests.sh similarity index 100% rename from test/run_tests.sh rename to test/run_unit_tests.sh