diff --git a/DATM/AtmBundleCreate.F90 b/DATM/AtmBundleCreate.F90 index c830dc6..0184ec3 100644 --- a/DATM/AtmBundleCreate.F90 +++ b/DATM/AtmBundleCreate.F90 @@ -1,4 +1,4 @@ -subroutine AtmBundleCreate(gcomp,importState, exportState, rc) +subroutine AtmBundleCreate(gcomp, exportState, rc) use ESMF @@ -7,7 +7,6 @@ subroutine AtmBundleCreate(gcomp,importState, exportState, rc) implicit none type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: importState type(ESMF_State) :: exportState integer, intent(out) :: rc diff --git a/DATM/AtmFieldUtils.F90 b/DATM/AtmFieldUtils.F90 index 18dce2f..f77b9fe 100644 --- a/DATM/AtmFieldUtils.F90 +++ b/DATM/AtmFieldUtils.F90 @@ -16,6 +16,7 @@ module AtmFieldUtils public :: AtmFieldsAdvertise, AtmFieldsRealize public :: AtmFieldCheck public :: AtmFieldDump + public :: State_SetScalar ! called by AtmInit, AtmRun public :: AtmForceFwd2Bak, AtmBundleCheck @@ -57,6 +58,13 @@ subroutine AtmFieldsAdvertise(state, field_defs, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return enddo + ! advertise scalars for cmeps + if (len_trim(scalar_field_name) > 0) then + call NUOPC_Advertise(state, standardName=trim(scalar_field_name), name=trim(scalar_field_name), rc=rc) + call ESMF_LogWrite("Advertise Field "// trim(scalar_field_name), ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + end subroutine AtmFieldsAdvertise !----------------------------------------------------------------------------- @@ -73,9 +81,7 @@ subroutine AtmFieldsRealize(state, grid, field_defs, tag, rc) type(ESMF_Field) :: field type(ESMF_StaggerLoc) :: staggerloc character(len=ESMF_MAXSTR) :: msgString - integer :: ii,nfields - logical :: connected rc = ESMF_SUCCESS call ESMF_LogWrite("User routine AtmFieldsRealize "//trim(tag)//" started", ESMF_LOGMSG_INFO) @@ -96,30 +102,41 @@ subroutine AtmFieldsRealize(state, grid, field_defs, tag, rc) name=trim(field_defs(ii)%shortname), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call NUOPC_Realize(state, grid, rc=rc) + call NUOPC_Realize(state, field=field, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_FieldGet(field, farrayPtr=field_defs(ii)%farrayPtr, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! initialize field_defs(ii)%farrayPtr = 0.0 - !do j = lbound(field_defs(ii)%farrayPtr,2),ubound(field_defs(ii)%farrayPtr,2) - ! do i = lbound(field_defs(ii)%farrayPtr,1),ubound(field_defs(ii)%farrayPtr,1) - ! field_defs(ii)%farrayPtr(i,j) = 0.0 - ! enddo - !enddo + + msgString = trim(tag)//" Field "// trim(field_defs(ii)%shortname) // " is connected on root pe" + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) enddo + ! realize scalars for cmeps + if (len_trim(scalar_field_name) > 0) then + call SetScalarField(field, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_Realize(state, field=field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + msgString = trim(tag)//" Field "// trim(scalar_field_name) // " is connected on root pe" + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + endif + call ESMF_LogWrite("User routine AtmFieldsRealize "//trim(tag)//" finished", ESMF_LOGMSG_INFO) end subroutine AtmFieldsRealize !------------------------------------------------------------------------------------- - subroutine AtmFieldCheck(importState, exportState, tag, rc) + subroutine AtmFieldCheck(exportState, tag, rc) use AtmInternalFields, only : iprnt, jprnt - type(ESMF_State) :: importState, exportState + type(ESMF_State) :: exportState character(len=*), intent( in) :: tag integer, intent(out) :: rc @@ -170,12 +187,10 @@ end subroutine AtmFieldCheck !----------------------------------------------------------------------------- - subroutine AtmFieldDump(importState, exportState, tag, timestr, rc) + subroutine AtmFieldDump(exportState, filename, rc) - type(ESMF_State) :: importState type(ESMF_State) :: exportState - character(len=*), intent( in) :: tag - character(len=*), intent( in) :: timestr + character(len=*), intent( in) :: filename integer, intent(out) :: rc ! Local variables @@ -183,7 +198,6 @@ subroutine AtmFieldDump(importState, exportState, tag, timestr, rc) integer :: ii,nfields character(len=ESMF_MAXSTR) :: varname - character(len=ESMF_MAXSTR) :: filename character(len=ESMF_MAXSTR) :: msgString ! Initialize return code @@ -191,6 +205,7 @@ subroutine AtmFieldDump(importState, exportState, tag, timestr, rc) call ESMF_LogWrite("User routine AtmFieldDump started", ESMF_LOGMSG_INFO) + ! Atm variables in exportState nfields = size(AtmBundleFields) do ii = 1,nfields call ESMF_StateGet(exportState, & @@ -198,9 +213,6 @@ subroutine AtmFieldDump(importState, exportState, tag, timestr, rc) field=field,rc=rc) varname = trim(AtmBundleFields(ii)%shortname) - if(trim(tag) .eq. 'before AtmRun')filename = 'field_atm_exportb_'//trim(timestr)//'.nc' - if(trim(tag) .eq. 'after AtmRun')filename = 'field_atm_exporta_'//trim(timestr)//'.nc' - write(msgString, '(a,i6)')'Writing exportState field '//trim(varname)//' to ' & //trim(filename) call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) @@ -209,11 +221,6 @@ subroutine AtmFieldDump(importState, exportState, tag, timestr, rc) fileName =trim(filename), & timeslice=1, & overwrite=.true., rc=rc) - !endif - !if(iicnt .eq. 1)then - ! write(msgString, *)'Writing exportState field ',trim(varname),' to ',trim(filename) - ! call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) - !endif enddo call ESMF_LogWrite("User routine AtmFieldDump finished", ESMF_LOGMSG_INFO) @@ -325,7 +332,7 @@ end subroutine AtmBundleCheck !----------------------------------------------------------------------------- - subroutine AtmBundleIntp(gcomp, importState, exportState, externalClock, hour, rc) + subroutine AtmBundleIntp(gcomp, exportState, externalClock, hour, rc) use AtmInternalFields, only : hfwd,hbak use AtmInternalFields, only : iprnt,jprnt @@ -333,7 +340,6 @@ subroutine AtmBundleIntp(gcomp, importState, exportState, externalClock, hour, r use AtmInternalFields, only : AtmBundleFwd, AtmBundleBak type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: importState type(ESMF_State) :: exportState type(ESMF_Clock) :: externalClock @@ -404,12 +410,14 @@ subroutine AtmBundleIntp(gcomp, importState, exportState, externalClock, hour, r ! real(AtmBundleFields(ii)%farrayPtr_fwd(ijloc(1),ijloc(2)),4) !call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) - write (msgString,*)' AtmIntp ',& - trim(AtmBundleFields(ii)%shortname),& - real(AtmBundleFields(ii)%farrayPtr(iprnt,jprnt),4),& - real(AtmBundleFields(ii)%farrayPtr_bak(iprnt,jprnt),4),& - real(AtmBundleFields(ii)%farrayPtr_fwd(iprnt,jprnt),4) - call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + if(dbug_flag > 0)then + write (msgString,*)' AtmIntp ',& + trim(AtmBundleFields(ii)%shortname),& + real(AtmBundleFields(ii)%farrayPtr(iprnt,jprnt),4),& + real(AtmBundleFields(ii)%farrayPtr_bak(iprnt,jprnt),4),& + real(AtmBundleFields(ii)%farrayPtr_fwd(iprnt,jprnt),4) + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + end if !write (msgString,*)' AtmBundleFields ',& ! trim(AtmBundleFields(ii)%field_name),' min,max,sum ',& @@ -422,4 +430,70 @@ subroutine AtmBundleIntp(gcomp, importState, exportState, externalClock, hour, r call ESMF_LogWrite("User routine AtmBundleIntp finished", ESMF_LOGMSG_INFO) end subroutine AtmBundleIntp + !----------------------------------------------------------------------------- + + !> Set scalar data from state for a particular name + subroutine State_SetScalar(value, scalar_id, State, mytask, scalar_name, scalar_count, rc) + real(ESMF_KIND_R8),intent(in) :: value + integer, intent(in) :: scalar_id + type(ESMF_State), intent(inout) :: State + integer, intent(in) :: mytask + character(len=*), intent(in) :: scalar_name + integer, intent(in) :: scalar_count + integer, intent(inout) :: rc !< return code + + ! local variables + type(ESMF_Field) :: field + real(ESMF_KIND_R8), pointer :: farrayptr(:,:) + character(len=*), parameter :: subname='(DATM: State_SetScalar)' + !-------------------------------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_StateGet(State, itemName=trim(scalar_name), field=field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (mytask == 0) then + call ESMF_FieldGet(field, farrayPtr=farrayptr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (scalar_id < 0 .or. scalar_id > scalar_count) then + call ESMF_LogSetError(ESMF_RC_ARG_BAD, & + msg=subname//": ERROR in scalar_id", line=__LINE__, file=__FILE__, rcToReturn=rc) + return + endif + + farrayptr(scalar_id,1) = value + endif + + end subroutine State_SetScalar + + !----------------------------------------------------------------------------- + + subroutine SetScalarField(field, rc) + + ! create a field with scalar data on the root pe + type(ESMF_Field), intent(inout) :: field + integer, intent(inout) :: rc + + ! local variables + type(ESMF_Distgrid) :: distgrid + type(ESMF_Grid) :: grid + character(len=*), parameter :: subname='(DATM: SetScalarField)' + + rc = ESMF_SUCCESS + + ! create a DistGrid with a single index space element, which gets mapped onto DE 0. + distgrid = ESMF_DistGridCreate(minIndex=(/1/), maxIndex=(/1/), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + grid = ESMF_GridCreate(distgrid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! num of scalar values + field = ESMF_FieldCreate(name=trim(scalar_field_name), grid=grid, typekind=ESMF_TYPEKIND_R8, & + ungriddedLBound=(/1/), ungriddedUBound=(/scalar_field_count/), gridToFieldMap=(/2/), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine SetScalarField end module AtmFieldUtils diff --git a/DATM/AtmForce.F90 b/DATM/AtmForce.F90 index 214d6b1..940bf3b 100644 --- a/DATM/AtmForce.F90 +++ b/DATM/AtmForce.F90 @@ -19,11 +19,15 @@ subroutine AtmForce(gcomp,exportState,externalClock,initmode,rc) type(ESMF_Time) :: currTime type(ESMF_Time) :: nextTime type(ESMF_TimeInterval) :: timeStep + type(ESMF_VM) :: vm integer(kind=ESMF_KIND_I4) :: year, month, day, hour, jday + integer :: mytask integer :: ii,nfields integer :: iii, iid, iiu + logical :: fexists + integer :: fpresent(1) = 0 character(len=ESMF_MAXSTR) :: varname character(len=ESMF_MAXSTR) :: filename @@ -45,6 +49,12 @@ subroutine AtmForce(gcomp,exportState,externalClock,initmode,rc) call ESMF_LogWrite("User routine AtmForce started", ESMF_LOGMSG_INFO) + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMGet(vm, localPet=mytask, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! at initialization, get the current forecast hour file, not the forward ! forecast hour if(initmode .eq. 0)then @@ -76,35 +86,52 @@ subroutine AtmForce(gcomp,exportState,externalClock,initmode,rc) call ESMF_TimeGet(nextTime,h_r8=hfwd,rc=rc) endif - write(msgString,'(3a,f12.3)')'using ',trim(filename),' at fwd clock hour ',real(hfwd,4) + write(msgString,'(3a,f12.3)')'using ',trim(filename),' at fwd clock hour ',hfwd call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) - ! read the Atm field data into the Fwd bundle - nfields = size(AtmBundleFields) - do ii = 1,nfields - if(AtmBundleFields(ii)%isPresent)then - varname = trim(AtmBundleFields(ii)%file_varname) - - ! get the '_fwd' field - call ESMF_FieldBundleGet(AtmBundleFwd, & - fieldName=trim(AtmBundleFields(ii)%field_name)//'_fwd', & - field=field, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - call ESMF_FieldRead(field, & - fileName=trim(filename), & - variableName = trim(varname), & - rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + fexists = .false. + if(mytask == 0)inquire(file=trim(filename), exist=fexists) + if(fexists) fpresent(1) = 1 + call ESMF_VMBroadCast(vm, fpresent, count=1, rootPet=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if(fpresent(1) == 1)fexists = .true. + + if(.not. fexists)then + if(mytask == 0)print *,'Cannot read file '//trim(filename)//': Aborting' + call ESMF_LogWrite('Cannot read file '//trim(filename)//': Aborting', ESMF_LOGMSG_INFO) + call ESMF_Finalize(endflag=ESMF_END_ABORT) + else + ! read the Atm field data into the Fwd bundle + nfields = size(AtmBundleFields) + do ii = 1,nfields + if(AtmBundleFields(ii)%isPresent)then + varname = trim(AtmBundleFields(ii)%file_varname) + + ! get the '_fwd' field + call ESMF_FieldBundleGet(AtmBundleFwd, & + fieldName=trim(AtmBundleFields(ii)%field_name)//'_fwd', & + field=field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_FieldRead(field, & + fileName=trim(filename), & + variableName = trim(varname), & + rc=rc) + if( rc /= ESMF_SUCCESS)then + call ESMF_LogWrite('Problem reading '//trim(filename), ESMF_LOGMSG_INFO) + call ESMF_Finalize(endflag=ESMF_END_ABORT) + endif + if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_FieldGet(field,farrayPtr=AtmBundleFields(ii)%farrayPtr_fwd,rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(field,farrayPtr=AtmBundleFields(ii)%farrayPtr_fwd,rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - write(msgString,'(i6,2a18,f14.5)')ii,' inside AtmForce ',trim(varname), & - AtmBundleFields(ii)%farrayPtr_fwd(iprnt,jprnt) - call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) - endif !isPresent - enddo + write(msgString,'(i6,2a18,f14.5)')ii,' inside AtmForce ',trim(varname), & + AtmBundleFields(ii)%farrayPtr_fwd(iprnt,jprnt) + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + endif !isPresent + enddo + end if ! Check for fields which are not Present but are needed ! Not very clean---would have been better to create this field in the forcing file diff --git a/DATM/AtmInternalFields.F90 b/DATM/AtmInternalFields.F90 index c10f70a..7df3c19 100644 --- a/DATM/AtmInternalFields.F90 +++ b/DATM/AtmInternalFields.F90 @@ -15,10 +15,14 @@ module AtmInternalFields !from model_configure integer, public :: iatm,jatm,nfhout + integer, public :: scalar_field_count = 0 + integer, public :: scalar_field_idx_grid_nx = 0 + integer, public :: scalar_field_idx_grid_ny = 0 real(kind=ESMF_KIND_R8), public :: dt_atmos character(len=ESMF_MAXSTR), public :: filename_base character(len=ESMF_MAXSTR), public :: cdate0 character(len=ESMF_MAXSTR), public :: dirpath = 'DATM_INPUT/' + character(len=ESMF_MAXSTR), public :: scalar_field_name = '' ! the forward and backward timestamps real(kind=ESMF_KIND_R8), public :: hfwd, hbak @@ -59,9 +63,11 @@ module AtmInternalFields type(AtmField_Definition), public :: AtmBundleFields(AtmFieldCount) - integer, public :: lPet, petCnt + integer, public :: lPet, petCnt + integer, public :: dbug_flag = 0 ! a diagnostic point to print at integer, public :: iprnt, jprnt + integer :: icnt ! called by AtmInit public :: AtmBundleSetUp @@ -325,13 +331,19 @@ subroutine AtmBundleSetUp if (ChkErr(rc,__LINE__,u_FILE_u)) return nfields = size(AtmBundleFields) + icnt = 0 do ii = 1,nfields call ESMF_ConfigGetAttribute(config=cfdata, & value=lvalue, & label=trim(AtmBundleFields(ii)%standard_name),rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return AtmBundleFields(ii)%isPresent=lvalue + icnt = icnt + 1 enddo + if(icnt .ne. nfields)then + call ESMF_LogWrite('Missing input fields in datm_data_table', ESMF_LOGMSG_INFO) + call ESMF_Finalize(endflag=ESMF_END_ABORT) + endif !----------------------------------------------------------------------------- ! check diff --git a/DATM/AtmModel.F90 b/DATM/AtmModel.F90 index 87d1a32..c04b317 100644 --- a/DATM/AtmModel.F90 +++ b/DATM/AtmModel.F90 @@ -4,6 +4,7 @@ module AtmModel use ESMF use AtmInternalFields, only : ChkErr + use AtmInternalFields, only : dbug_flag use AtmInternalFields, only : hfwd, hbak, nfhout use AtmFieldUtils, only : AtmForceFwd2Bak, AtmBundleCheck use AtmFieldUtils, only : AtmBundleIntp @@ -20,12 +21,11 @@ module AtmModel contains - subroutine AtmInit(gcomp, importState, exportState, externalClock, rc) + subroutine AtmInit(gcomp, exportState, externalClock, rc) use AtmInternalFields type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: importState type(ESMF_State) :: exportState type(ESMF_Clock) :: externalClock integer, intent(out) :: rc @@ -73,26 +73,25 @@ subroutine AtmInit(gcomp, importState, exportState, externalClock, rc) ! initialize the fwd and bak fields as special case at initialzation call AtmForce(gcomp,exportState,externalClock,0,rc) - call AtmBundleCheck('after AtmForce',rc) + if(dbug_flag > 5)call AtmBundleCheck('after AtmForce',rc) ! copy the fwd timestamp to the bak timestamp hbak = hfwd call AtmForceFwd2Bak(rc) - call AtmBundleCheck('after Fwd2Bak',rc) + if(dbug_flag > 5)call AtmBundleCheck('after Fwd2Bak',rc) ! reload the fwd call AtmForce(gcomp,exportState,externalClock,0,rc) - call AtmBundleCheck('after AtmForce',rc) + if(dbug_flag > 5)call AtmBundleCheck('after AtmForce',rc) !time interpolate between fwd & bak values - call AtmBundleIntp(gcomp, importState, exportState, externalClock, 0.0d8, rc) + call AtmBundleIntp(gcomp, exportState, externalClock, 0.0d8, rc) call ESMF_LogWrite("User run routine AtmInit finished", ESMF_LOGMSG_INFO) end subroutine AtmInit !----------------------------------------------------------------------------- - subroutine AtmRun(gcomp, importState, exportState, externalClock, rc) + subroutine AtmRun(gcomp, exportState, externalClock, rc) type(ESMF_GridComp) :: gcomp - type(ESMF_State) :: importState type(ESMF_State) :: exportState type(ESMF_Clock) :: externalClock integer, intent(out) :: rc @@ -138,9 +137,9 @@ subroutine AtmRun(gcomp, importState, exportState, externalClock, rc) write(msgString,*)'AtmRun: hbkd,hour,hfwd ', hbak,hour,hfwd call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO, rc=rc) - call AtmBundleCheck('after AtmRun',rc) + if(dbug_flag > 5)call AtmBundleCheck('after AtmRun',rc) !time interpolate between fwd & bak values - call AtmBundleIntp(gcomp, importState, exportState, externalClock, hour, rc) + call AtmBundleIntp(gcomp, exportState, externalClock, hour, rc) call ESMF_LogWrite("User run routine AtmRun finished", ESMF_LOGMSG_INFO) diff --git a/DATM/datm.F90 b/DATM/datm.F90 index c54bc9b..836031d 100644 --- a/DATM/datm.F90 +++ b/DATM/datm.F90 @@ -17,6 +17,7 @@ module DAtm use AtmFieldUtils, only : AtmFieldsAdvertise, AtmFieldsRealize use AtmFieldUtils, only : AtmFieldDump use AtmFieldUtils, only : AtmFieldCheck + use AtmFieldUtils, only : State_SetScalar use AtmGridUtils, only : WriteCoord, WriteMask ! AtmInit called by InitializeP2, AtmRun called by ModelAdvance @@ -106,11 +107,14 @@ end subroutine SetServices subroutine InitializeP0(model, importState, exportState, externalClock, rc) type(ESMF_GridComp) :: model - type(ESMF_State) :: importState, exportState + type(ESMF_State) :: importState + type(ESMF_State) :: exportState type(ESMF_Clock) :: externalClock integer, intent(out) :: rc + logical :: isPresent, isSet - character(len=10) :: value + integer :: iostat + character(len=64) :: value character(len=ESMF_MAXSTR) :: msgString rc = ESMF_SUCCESS @@ -158,6 +162,63 @@ subroutine InitializeP0(model, importState, exportState, externalClock, rc) write(msgString,'(A,l6)')'DATM Profile_memory = ',profile_memory call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + + scalar_field_name = "" + call NUOPC_CompAttributeGet(model, name="ScalarFieldName", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + scalar_field_name = trim(value) + call ESMF_LogWrite('DATM: ScalarFieldName = '//trim(scalar_field_name), ESMF_LOGMSG_INFO) + endif + + scalar_field_count = 0 + call NUOPC_CompAttributeGet(model, name="ScalarFieldCount", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(value, '(i)', iostat=iostat) scalar_field_count + if (iostat /= 0) then + call ESMF_LogSetError(ESMF_RC_ARG_BAD, & + msg="DATM : ScalarFieldCount not an integer: "//trim(value), & + line=__LINE__, file=__FILE__, rcToReturn=rc) + return + endif + write(msgString,*) scalar_field_count + call ESMF_LogWrite('DATM: ScalarFieldCount = '//trim(msgString), ESMF_LOGMSG_INFO) + endif + + scalar_field_idx_grid_nx = 0 + call NUOPC_CompAttributeGet(model, name="ScalarFieldIdxGridNX", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(value, '(i)', iostat=iostat) scalar_field_idx_grid_nx + if (iostat /= 0) then + call ESMF_LogSetError(ESMF_RC_ARG_BAD, & + msg="DATM : ScalarFieldIdxGridNX not an integer: "//trim(value), & + line=__LINE__, file=__FILE__, rcToReturn=rc) + return + endif + write(msgString,*) scalar_field_idx_grid_nx + call ESMF_LogWrite('DATM: ScalarFieldIdxGridNX = '//trim(msgString), ESMF_LOGMSG_INFO) + endif + + scalar_field_idx_grid_ny = 0 + call NUOPC_CompAttributeGet(model, name="ScalarFieldIdxGridNY", value=value, & + isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(value, '(i)', iostat=iostat) scalar_field_idx_grid_ny + if (iostat /= 0) then + call ESMF_LogSetError(ESMF_RC_ARG_BAD, & + msg="DATM : ScalarFieldIdxGridNY not an integer: "//trim(value), & + line=__LINE__, file=__FILE__, rcToReturn=rc) + return + endif + write(msgString,*) scalar_field_idx_grid_ny + call ESMF_LogWrite('DATM: ScalarFieldIdxGridNY = '//trim(msgString), ESMF_LOGMSG_INFO) + endif #endif call ESMF_LogWrite("User initialize routine InitP0 Atm finished", ESMF_LOGMSG_INFO) @@ -169,7 +230,8 @@ end subroutine InitializeP0 subroutine InitializeP1(model, importState, exportState, externalClock, rc) type(ESMF_GridComp) :: model - type(ESMF_State) :: importState, exportState + type(ESMF_State) :: importState + type(ESMF_State) :: exportState type(ESMF_Clock) :: externalClock integer, intent(out) :: rc @@ -177,6 +239,7 @@ subroutine InitializeP1(model, importState, exportState, externalClock, rc) type(ESMF_Config) :: cf real(ESMF_KIND_R8) :: medAtmCouplingIntervalSec character(ESMF_MAXSTR) :: msgString + character(20) :: cvalue rc = ESMF_SUCCESS @@ -225,7 +288,6 @@ subroutine InitializeP1(model, importState, exportState, externalClock, rc) write(msgString,'(a,i6)')'Model configure found with nfhout = ',nfhout call ESMF_LogWrite(msgString, ESMF_LOGMSG_INFO) - call ESMF_ConfigGetAttribute(config=cf, & value=filename_base, & label='filename_base:',rc=rc) @@ -250,6 +312,12 @@ subroutine InitializeP1(model, importState, exportState, externalClock, rc) medAtmCouplingIntervalSec call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + call NUOPC_CompAttributeGet(model, name='DebugFlag', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) dbug_flag + write(msgString,'(a,i6)')'DebugFlag = ',dbug_flag + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + call ESMF_LogWrite("User initialize routine InitP1 Atm finished", ESMF_LOGMSG_INFO) end subroutine InitializeP1 @@ -259,8 +327,11 @@ end subroutine InitializeP1 subroutine InitializeP2(model, importState, exportState, externalClock, rc) type(ESMF_GridComp) :: model - type(ESMF_State) :: importState, exportState + type(ESMF_State) :: importState + type(ESMF_State) :: exportState type(ESMF_Clock) :: externalClock + type(ESMF_Time) :: currTime + type(ESMF_VM) :: vm integer, intent(out) :: rc ! local variables @@ -268,14 +339,22 @@ subroutine InitializeP2(model, importState, exportState, externalClock, rc) type(ESMF_Grid) :: gridOut type(ESMF_Field) :: field character(ESMF_MAXSTR) :: msgString + character(ESMF_MAXSTR) :: timestr character(ESMF_MAXSTR) :: fname + integer :: localPet, npet, mpicom integer :: ii, nfields rc = ESMF_SUCCESS call ESMF_LogWrite("User initialize routine InitP2 Atm started", ESMF_LOGMSG_INFO) + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMGet(vm, petCount=npet, mpiCommunicator=mpicom, localPet=localPet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockPrint(externalClock, options="currTime", & preString="InitP2 Atm CLOCK_EARTH current: ", & unit=msgString) @@ -313,13 +392,13 @@ subroutine InitializeP2(model, importState, exportState, externalClock, rc) !call ESMF_GridCompPrint(model, rc=rc) ! Create and fill the AtmBundle - call AtmBundleCreate(model, importState, exportState, rc) + call AtmBundleCreate(model, exportState, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call AtmFieldsRealize(exportState, gridOut, AtmBundleFields, 'Atm Export', rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call AtmInit(model, importState, exportState, externalClock, rc) + call AtmInit(model, exportState, externalClock, rc) ! AtmInit calls AtmForce and loads the values for the first integration ! timestep, so..... @@ -338,6 +417,25 @@ subroutine InitializeP2(model, importState, exportState, externalClock, rc) call ESMF_LogWrite(trim(AtmBundleFields(ii)%shortname)//' set to Updated', ESMF_LOGMSG_INFO) enddo !ii + + ! set scalars for cmeps + if(len_trim(scalar_field_name) > 0) then + call State_SetScalar(dble(iatm),scalar_field_idx_grid_nx, exportState, localPet, & + scalar_field_name, scalar_field_count, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call State_SetScalar(dble(jatm),scalar_field_idx_grid_ny, exportState, localPet, & + scalar_field_name, scalar_field_count, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_StateGet(exportState, itemName=trim(scalar_field_name), 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 + + call ESMF_LogWrite(trim(scalar_field_name)//' set to Updated', ESMF_LOGMSG_INFO) + end if ! the component needs to indicate that it is fully done with ! initializing its data: @@ -349,7 +447,17 @@ subroutine InitializeP2(model, importState, exportState, externalClock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_LogWrite('Atm InitializeDataComplete', ESMF_LOGMSG_INFO) - call AtmFieldCheck(importState, exportState, 'InitP2 Atm', rc) + if(dbug_flag > 5)call AtmFieldCheck(exportState, 'InitP2 Atm', rc) + + ! the initial fields at model startup + if(dumpfields)then + call ESMF_ClockGet(externalClock, currTime=currTime, rc = rc) + call ESMF_TimeGet(currTime, timestring=timestr, rc=rc) + + fname = 'field_atm_exporta_'//trim(timestr)//'.nc' + call AtmFieldDump(exportState, trim(fname), rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif call ESMF_LogWrite("User initialize routine InitP2 Atm finished", ESMF_LOGMSG_INFO) @@ -363,13 +471,14 @@ subroutine ModelAdvance(model, rc) integer, intent(out) :: rc ! local variables - type(ESMF_State) :: importState, exportState + type(ESMF_State) :: exportState type(ESMF_Clock) :: modelClock type(ESMF_Time) :: stopTime type(ESMF_Time) :: startTime type(ESMF_Time) :: currTime type(ESMF_TimeInterval) :: timeStep + character(len=ESMF_MAXSTR) :: fname character(len=ESMF_MAXSTR) :: msgString character(len=ESMF_MAXSTR) :: export_timestr @@ -377,10 +486,9 @@ subroutine ModelAdvance(model, rc) call ESMF_LogWrite("User routine ModelAdvance Atm started", ESMF_LOGMSG_INFO) - ! query the Component for its clock, importState and exportState + ! query the Component for its clock and exportState call NUOPC_ModelGet(model, & modelClock=modelClock, & - importState=importState, & exportState=exportState, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -395,30 +503,34 @@ subroutine ModelAdvance(model, rc) currTime=currTime, & startTime=startTime, & stopTime=stopTime, & + timeStep=timeStep, & rc=rc) - call ESMF_ClockPrint(modelClock, options="currTime", & + call ESMF_TimePrint(currTime, & preString="ModelAdvance DATM with CLOCK current: ", & unit=msgString) call ESMF_LogWrite(msgString, ESMF_LOGMSG_INFO) - call ESMF_ClockPrint(modelClock, options="stopTime", & + call ESMF_TimePrint(currTime + timeStep, & + preString="ModelAdvance DATM with CLOCK advance to: ", & + unit=msgString, rc=rc) + call ESMF_LogWrite(trim(msgString), ESMF_LOGMSG_INFO) + call ESMF_TimePrint(stopTime, & preString="ModelAdvance DATM with CLOCK stop: ", & unit=msgString) call ESMF_LogWrite(msgString, ESMF_LOGMSG_INFO) - call ESMF_ClockGet(modelClock, currTime=currTime, timeStep=timeStep, rc=rc) - ! TODO: why is this the export time? - call ESMF_TimeGet(currTime, timestring=export_timestr, rc=rc) + call ESMF_TimeGet(currTime+timestep, timestring=export_timestr, rc=rc) ! Run the component - call AtmRun(model, importState, exportState, modelClock, rc) + call AtmRun(model, exportState, modelClock, rc) ! Check Values - call AtmFieldCheck(importState, exportState, 'after AtmRun', rc) + if(dbug_flag > 5)call AtmFieldCheck(exportState, 'after AtmRun', rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if(dumpfields)then - call AtmFieldDump(importstate, exportstate, 'after AtmRun', trim(export_timestr), rc) + fname = 'field_atm_exporta_'//trim(export_timestr)//'.nc' + call AtmFieldDump(exportState, trim(fname), rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return endif @@ -426,39 +538,6 @@ subroutine ModelAdvance(model, rc) end subroutine ModelAdvance - ! like cice_cap, which had the simplest clock settings I could find - !----------------------------------------------------------------------------- - - subroutine SetClock(model, rc) - - type(ESMF_GridComp) :: model - integer, intent(out) :: rc - - ! local variables - type(ESMF_Clock) :: clock - type(ESMF_TimeInterval) :: stabilityTimeStep, timeStep - - rc = ESMF_SUCCESS - - ! query the Component for its clock - call ESMF_GridCompGet(model, clock=clock, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - call ESMF_TimeIntervalSet(timestep, s_r8=dt_atmos, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - call ESMF_ClockSet(clock, timestep=timestep, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - ! initialize internal clock - ! here: parent Clock and stability timeStep determine actual model timeStep - call ESMF_TimeIntervalSet(stabilityTimeStep, s_r8=dt_atmos, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call NUOPC_CompSetClock(model, clock, stabilityTimeStep, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - end subroutine SetClock - !----------------------------------------------------------------------------- subroutine SetRunClock(model, rc) @@ -468,10 +547,13 @@ subroutine SetRunClock(model, rc) ! local variables type(ESMF_Clock) :: modelClock, driverClock - type(ESMF_Time) :: currTime - type(ESMF_TimeInterval) :: timeStep + type(ESMF_Time) :: mcurrtime, dcurrtime + type(ESMF_Time) :: mstoptime, dstoptime + type(ESMF_TimeInterval) :: mtimestep, dtimestep + character(len=ESMF_MAXSTR) :: mtimestring, dtimestring character(len=ESMF_MAXSTR) :: msgString + character(len=ESMF_MAXSTR) :: subname = "SetRunClock" rc = ESMF_SUCCESS #ifndef coupled @@ -485,36 +567,40 @@ subroutine SetRunClock(model, rc) driverClock=driverClock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - ! set the modelClock to have the current start time as the driverClock - call ESMF_ClockGet(driverClock, currTime=currTime, timeStep=timeStep, rc=rc) + call ESMF_ClockGet(driverClock, currTime=dcurrtime, timeStep=dtimestep, & + stopTime=dstoptime, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_TimeIntervalSet(timestep, s_r8=dt_atmos, rc=rc) + call ESMF_ClockGet(modelClock, currTime=mcurrtime, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_ClockSet(modelClock, currTime=currTime, timeStep=timestep, rc=rc) + call ESMF_TimeIntervalSet(mtimestep, s_r8=dt_atmos, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_ClockPrint(modelClock, options="currTime", & - preString="entering SetRunClock DATM with modelClock current: ", & - unit=msgString) - call ESMF_LogWrite(msgString, ESMF_LOGMSG_INFO) - call ESMF_ClockPrint(driverClock, options="currTime", & - preString="entering SetRunClock DATM with driverClock current: ", & - unit=msgString) - call ESMF_LogWrite(msgString, ESMF_LOGMSG_INFO) + !-------------------------------- + ! check that the current time in the model and driver are the same + !-------------------------------- - call ESMF_ClockPrint(modelClock, options="stopTime", & - preString="entering SetRunClock DATM with modelClock stop: ", & - unit=msgString) - call ESMF_LogWrite(msgString, ESMF_LOGMSG_INFO) - call ESMF_ClockPrint(driverClock, options="stopTime", & - preString="entering SetRunClock DATM with driverClock stop: ", & - unit=msgString) - call ESMF_LogWrite(msgString, ESMF_LOGMSG_INFO) + if (mcurrtime /= dcurrtime) then + call ESMF_TimeGet(dcurrtime, timeString=dtimestring, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet(mcurrtime, timeString=mtimestring, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogSetError(ESMF_RC_VAL_WRONG, & + msg=trim(subname)//": ERROR in time consistency: "//trim(dtimestring)//" != "//trim(mtimestring), & + line=__LINE__, file=__FILE__, rcToReturn=rc) + return + endif + + !-------------------------------- + ! force model clock currtime and timestep to match driver and set stoptime + !-------------------------------- + + mstoptime = mcurrtime + dtimestep - ! check and set the component clock against the driver clock - call NUOPC_CompCheckSetClock(model, driverClock, rc=rc) + call ESMF_ClockSet(modelClock, currTime=dcurrtime, timeStep=dtimestep, stopTime=mstoptime, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_LogWrite("User routine SetRunClock Atm finished", ESMF_LOGMSG_INFO)