diff --git a/cesm/driver/ensemble_driver.F90 b/cesm/driver/ensemble_driver.F90
index 58b9d58a1..1e91236ca 100644
--- a/cesm/driver/ensemble_driver.F90
+++ b/cesm/driver/ensemble_driver.F90
@@ -16,7 +16,13 @@ module Ensemble_driver
public :: SetServices
private :: SetModelServices
+ private :: ensemble_finalize
+ integer, allocatable :: asyncio_petlist(:)
+ logical :: asyncio_task=.false.
+ logical :: asyncIO_available=.false.
+ integer :: number_of_members
+ integer :: inst ! ensemble instance containing this task
character(*),parameter :: u_FILE_u = &
__FILE__
@@ -26,9 +32,12 @@ module Ensemble_driver
subroutine SetServices(ensemble_driver, rc)
- use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSpecialize
+ use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSpecialize, NUOPC_CompAttributeSet
+ use NUOPC , only : NUOPC_CompAttributeGet
use NUOPC_Driver , only : driver_routine_SS => SetServices
use NUOPC_Driver , only : ensemble_label_SetModelServices => label_SetModelServices
+ use NUOPC_Driver , only : ensemble_label_PostChildrenAdvertise => label_PostChildrenAdvertise
+ use NUOPC_Driver , only : label_Finalize
use ESMF , only : ESMF_GridComp, ESMF_GridCompSet
use ESMF , only : ESMF_Config, ESMF_ConfigCreate, ESMF_ConfigLoadFile
use ESMF , only : ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO
@@ -38,6 +47,7 @@ subroutine SetServices(ensemble_driver, rc)
! local variables
type(ESMF_Config) :: config
+ logical :: isPresent
character(len=*), parameter :: subname = "(ensemble_driver.F90:SetServices)"
!---------------------------------------
@@ -53,6 +63,14 @@ subroutine SetServices(ensemble_driver, rc)
specRoutine=SetModelServices, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
+ ! PostChildrenAdvertise is a NUOPC specialization which happens after Advertize but before Realize
+ ! We have overloaded this specialization location to initilize IO.
+ ! So after all components have called Advertise but before any component calls Realize
+ ! IO will be initialized and any async IO tasks will be split off to the PIO async IO driver.
+ call NUOPC_CompSpecialize(ensemble_driver, specLabel=ensemble_label_PostChildrenAdvertise, &
+ specRoutine=InitializeIO, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+
! Create, open and set the config
config = ESMF_ConfigCreate(rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
@@ -63,6 +81,26 @@ subroutine SetServices(ensemble_driver, rc)
call ESMF_GridCompSet(ensemble_driver, config=config, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
+ ! NUOPC component drivers end the initialization process with an internal call to InitializeDataResolution.
+ ! The ensemble_driver does not need to InitializeDataResolution and doing so will cause a hang
+ ! if asyncronous IO is used. This attribute is available after ESMF8.4.0b03 to toggle that control.
+ ! Cannot use asyncIO with older ESMF versions.
+ call NUOPC_CompAttributeGet(ensemble_driver, name="InitializeDataResolution", &
+ isPresent=isPresent, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+
+ if(isPresent) then
+ call ESMF_LogWrite(trim(subname)//": setting InitializeDataResolution false", ESMF_LOGMSG_INFO)
+ call NUOPC_CompAttributeSet(ensemble_driver, name="InitializeDataResolution", value="false", rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ asyncIO_available = .true.
+ call ESMF_LogWrite(trim(subname)//": asyncio is available", ESMF_LOGMSG_INFO)
+ endif
+ ! Set a finalize method, it calls pio_finalize
+ call NUOPC_CompSpecialize(ensemble_driver, specLabel=label_Finalize, &
+ specRoutine=ensemble_finalize, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+
call ESMF_LogWrite(trim(subname)//": done", ESMF_LOGMSG_INFO)
end subroutine SetServices
@@ -99,9 +137,13 @@ subroutine SetModelServices(ensemble_driver, rc)
character(len=512) :: logfile
logical :: read_restart
character(len=CS) :: read_restart_string
- integer :: inst
- integer :: number_of_members
integer :: ntasks_per_member
+ integer :: iopetcnt
+ integer :: petcnt
+ logical :: comp_task
+ integer :: pio_asyncio_ntasks
+ integer :: pio_asyncio_stride
+ integer :: pio_asyncio_rootpe
integer :: Global_Comm
character(CL) :: start_type ! Type of startup
character(len=7) :: drvrinst
@@ -196,13 +238,25 @@ subroutine SetModelServices(ensemble_driver, rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
read(cvalue,*) number_of_members
+ call NUOPC_CompAttributeGet(ensemble_driver, name="pio_asyncio_ntasks", value=cvalue, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) pio_asyncio_ntasks
+
+ call NUOPC_CompAttributeGet(ensemble_driver, name="pio_asyncio_stride", value=cvalue, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) pio_asyncio_stride
+
+ call NUOPC_CompAttributeGet(ensemble_driver, name="pio_asyncio_rootpe", value=cvalue, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) pio_asyncio_rootpe
+
call ESMF_VMGet(vm, localPet=localPet, PetCount=PetCount, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
- ntasks_per_member = PetCount/number_of_members
- if(ntasks_per_member*number_of_members .ne. PetCount) then
+ ntasks_per_member = PetCount/number_of_members - pio_asyncio_ntasks
+ if(modulo(PetCount-pio_asyncio_ntasks*number_of_members, number_of_members) .ne. 0) then
write (msgstr,'(a,i5,a,i3,a,i3,a)') &
- "PetCount (",PetCount,") must be evenly divisable by number of members (",number_of_members,")"
+ "PetCount (",PetCount,") - Async IOtasks (",pio_asyncio_ntasks*number_of_members,") must be evenly divisable by number of members (",number_of_members,")"
call ESMF_LogSetError(ESMF_RC_ARG_BAD, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc)
return
endif
@@ -212,33 +266,70 @@ subroutine SetModelServices(ensemble_driver, rc)
!-------------------------------------------
allocate(petList(ntasks_per_member))
- ! We need to loop over instances
- call t_startf('compute_drivers')
- do inst = 1, number_of_members
-
- ! Determine pet list for driver instance
- petList(1) = (inst-1) * ntasks_per_member
- do n=2,ntasks_per_member
- petList(n) = petList(n-1) + 1
+ allocate(asyncio_petlist(pio_asyncio_ntasks))
+ !
+ ! Logic for asyncio variables is handled in cmeps buildnml.
+ ! here we assume that pio_asyncio_stride and pio_asyncio_ntasks are only set
+ ! if asyncio is enabled.
+ !
+ inst = localPet/(ntasks_per_member+pio_asyncio_ntasks) + 1
+
+ petcnt=1
+ iopetcnt = 1
+ comp_task = .false.
+ asyncio_task = .false.
+ ! Determine pet list for driver instance
+ if(pio_asyncio_ntasks > 0) then
+ do n=pio_asyncio_rootpe,pio_asyncio_rootpe+pio_asyncio_stride*(pio_asyncio_ntasks-1),pio_asyncio_stride
+ asyncio_petlist(iopetcnt) = (inst-1)*(ntasks_per_member+pio_asyncio_ntasks) + n
+ if(asyncio_petlist(iopetcnt) == localPet) asyncio_task = .true.
+ iopetcnt = iopetcnt+1
enddo
-
- ! Add driver instance to ensemble driver
- write(drvrinst,'(a,i4.4)') "ESM",inst
- call NUOPC_DriverAddComp(ensemble_driver, drvrinst, ESMSetServices, petList=petList, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- enddo
- call t_stopf('compute_drivers')
-
- inst = localPet/ntasks_per_member + 1
- petList(1) = (inst-1) * ntasks_per_member
- do n=2,ntasks_per_member
- petList(n) = petList(n-1) + 1
+ iopetcnt = 1
+ endif
+ do n=0,ntasks_per_member+pio_asyncio_ntasks-1
+ if(pio_asyncio_ntasks > 0) then
+ if( asyncio_petlist(iopetcnt)==(inst-1)*(ntasks_per_member+pio_asyncio_ntasks) + n) then
+ ! Here if asyncio is true and this is an io task
+ iopetcnt = iopetcnt+1
+ else if(petcnt <= ntasks_per_member) then
+ ! Here if this is a compute task
+ petList(petcnt) = n + (inst-1)*(ntasks_per_member + pio_asyncio_ntasks)
+ if (petList(petcnt) == localPet) then
+ comp_task=.true.
+ endif
+ petcnt = petcnt+1
+ else
+ msgstr = "ERROR task cannot be neither a compute task nor an asyncio task"
+ call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc)
+ return ! bail out
+ endif
+ else
+ ! Here if asyncio is false
+ petList(petcnt) = (inst-1)*ntasks_per_member + n
+ if (petList(petcnt) == localPet) comp_task=.true.
+ petcnt = petcnt+1
+ endif
enddo
- if (localpet >= petlist(1) .and. localpet <= petlist(ntasks_per_member)) then
- write(drvrinst,'(a,i4.4)') "ESM",inst
- call NUOPC_DriverGetComp(ensemble_driver, drvrinst, comp=driver, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
+ if(comp_task .and. asyncio_task) then
+ msgstr = "ERROR task cannot be both a compute task and an asyncio task"
+ call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc)
+ return ! bail out
+ elseif (.not. comp_task .and. .not. asyncio_task) then
+ msgstr = "ERROR task is nether a compute task nor an asyncio task"
+ call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc)
+ return ! bail out
+ endif
+ ! Add driver instance to ensemble driver
+ write(drvrinst,'(a,i4.4)') "ESM",inst
+
+ call NUOPC_DriverAddComp(ensemble_driver, drvrinst, ESMSetServices, petList=petList, comp=driver, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ write(msgstr, *) ": driver added on PETS ",petlist(1),' to ',petlist(petcnt-1)
+ call ESMF_LogWrite(trim(subname)//msgstr)
+ maintask = .false.
+ if (comp_task) then
if(number_of_members > 1) then
call NUOPC_CompAttributeAdd(driver, attrList=(/'inst_suffix'/), rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
@@ -265,7 +356,8 @@ subroutine SetModelServices(ensemble_driver, rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
! Set the driver log to the driver task 0
- if (mod(localPet, ntasks_per_member) == 0) then
+
+ if (localPet == petList(1)) then
call NUOPC_CompAttributeGet(driver, name="diro", value=diro, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
call NUOPC_CompAttributeGet(driver, name="logfile", value=logfile, rc=rc)
@@ -274,15 +366,12 @@ subroutine SetModelServices(ensemble_driver, rc)
maintask = .true.
else
logUnit = 6
- maintask = .false.
endif
call shr_log_setLogUnit (logunit)
-
- ! Create a clock for each driver instance
- call esm_time_clockInit(ensemble_driver, driver, logunit, maintask, rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
-
endif
+ ! Create a clock for each driver instance
+ call esm_time_clockInit(ensemble_driver, driver, logunit, maintask, rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
deallocate(petList)
call t_stopf(subname)
@@ -291,4 +380,76 @@ subroutine SetModelServices(ensemble_driver, rc)
end subroutine SetModelServices
+ subroutine InitializeIO(ensemble_driver, rc)
+ use ESMF, only: ESMF_GridComp, ESMF_LOGMSG_INFO, ESMF_LogWrite
+ use ESMF, only: ESMF_SUCCESS, ESMF_VM, ESMF_GridCompGet, ESMF_VMGet
+ use ESMF, only: ESMF_CONFIG, ESMF_GridCompIsPetLocal, ESMF_State, ESMF_Clock
+ use NUOPC, only: NUOPC_CompAttributeGet, NUOPC_CompGet
+ use NUOPC_DRIVER, only: NUOPC_DriverGetComp
+ use driver_pio_mod , only: driver_pio_init, driver_pio_component_init
+#ifndef NO_MPI2
+ use MPI, only : MPI_Comm_split, MPI_UNDEFINED
+#endif
+ type(ESMF_GridComp) :: ensemble_driver
+ type(ESMF_VM) :: ensemble_vm
+ integer, intent(out) :: rc
+ character(len=*), parameter :: subname = '('//__FILE__//':InitializeIO)'
+ type(ESMF_GridComp), pointer :: dcomp(:)
+ integer :: iam
+ integer :: Global_Comm, Instance_Comm
+ integer :: drv
+ integer :: PetCount
+ integer :: key, color, i
+ character(len=8) :: compname
+
+ rc = ESMF_SUCCESS
+ call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
+ call shr_log_setLogUnit (logunit)
+
+ call ESMF_GridCompGet(ensemble_driver, vm=ensemble_vm, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_VMGet(ensemble_vm, localpet=iam, mpiCommunicator=Global_Comm, PetCount=PetCount, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ if(number_of_members > 1) then
+ color = inst
+ key = modulo(iam, PetCount/number_of_members)
+#ifndef NO_MPI2
+ call MPI_Comm_split(Global_Comm, color, key, Instance_Comm, rc)
+#endif
+ do i=1,size(asyncio_petlist)
+ asyncio_petList(i) = modulo(asyncio_petList(i), PetCount/number_of_members)
+ enddo
+ else
+ Instance_Comm = Global_Comm
+ endif
+ nullify(dcomp)
+ call NUOPC_DriverGetComp(ensemble_driver, complist=dcomp, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call NUOPC_CompGet(dcomp(1), name=compname, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_LogWrite(trim(subname)//": call driver_pio_init "//compname, ESMF_LOGMSG_INFO)
+ call driver_pio_init(dcomp(1), rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+
+ call ESMF_LogWrite(trim(subname)//": call driver_pio_component_init "//compname, ESMF_LOGMSG_INFO)
+ call driver_pio_component_init(dcomp(1), Instance_Comm, asyncio_petlist, rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_LogWrite(trim(subname)//": driver_pio_component_init done "//compname, ESMF_LOGMSG_INFO)
+
+ deallocate(dcomp)
+ deallocate(asyncio_petlist)
+ call ESMF_LogWrite(trim(subname)//": done", ESMF_LOGMSG_INFO)
+ end subroutine InitializeIO
+
+ subroutine ensemble_finalize(ensemble_driver, rc)
+ use ESMF, only : ESMF_GridComp, ESMF_SUCCESS
+ use driver_pio_mod, only: driver_pio_finalize
+ type(ESMF_GridComp) :: Ensemble_driver
+ integer, intent(out) :: rc
+ rc = ESMF_SUCCESS
+ call shr_log_setLogUnit (logunit)
+ call driver_pio_finalize()
+
+ end subroutine ensemble_finalize
end module Ensemble_driver
diff --git a/cesm/driver/esm.F90 b/cesm/driver/esm.F90
index da2f6f6d3..02970d31e 100644
--- a/cesm/driver/esm.F90
+++ b/cesm/driver/esm.F90
@@ -237,6 +237,7 @@ subroutine SetRunSequence(driver, rc)
rc = ESMF_SUCCESS
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
+ call shr_log_setLogunit(logunit)
!--------
! Run Sequence and Connectors
@@ -335,6 +336,7 @@ recursive subroutine ModifyCplLists(driver, importState, exportState, clock, rc)
rc = ESMF_SUCCESS
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
+ call shr_log_setLogunit(logunit)
call ESMF_LogWrite("Driver is in ModifyCplLists()", ESMF_LOGMSG_INFO, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
@@ -430,6 +432,7 @@ subroutine InitAttributes(driver, rc)
rc = ESMF_SUCCESS
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
+ call shr_log_setLogunit(logunit)
!----------------------------------------------------------
! Initialize options for reproducible sums
@@ -617,6 +620,7 @@ subroutine AddAttributes(gcomp, driver, config, compid, compname, inst_suffix, n
rc = ESMF_Success
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
+ call shr_log_setLogunit(logunit)
!------
! Add compid to gcomp attributes
@@ -718,6 +722,7 @@ subroutine ReadAttributes(gcomp, config, label, relaxedflag, formatprint, rc)
!-------------------------------------------
rc = ESMF_SUCCESS
+ call shr_log_setLogunit(logunit)
if (present(relaxedflag)) then
attrFF = NUOPC_FreeFormatCreate(config, label=trim(label), relaxedflag=.true., rc=rc)
@@ -785,7 +790,6 @@ subroutine esm_init_pelayout(driver, maxthreads, rc)
use mpi , only : MPI_COMM_NULL, mpi_comm_size
#endif
use mct_mod , only : mct_world_init
- use driver_pio_mod , only : driver_pio_init, driver_pio_component_init
#ifdef MED_PRESENT
use med_internalstate_mod , only : med_id
@@ -870,6 +874,7 @@ subroutine esm_init_pelayout(driver, maxthreads, rc)
integer :: rank, nprocs, ierr
character(len=*), parameter :: subname = "(esm_pelayout.F90:esm_init_pelayout)"
!---------------------------------------
+ call shr_log_setLogunit(logunit)
rc = ESMF_SUCCESS
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
@@ -908,11 +913,6 @@ subroutine esm_init_pelayout(driver, maxthreads, rc)
inst_suffix = ""
endif
- ! Initialize PIO
- ! This reads in the pio parameters that are independent of component
- call driver_pio_init(driver, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
-
allocate(comms(componentCount+1), comps(componentCount+1))
comps(1) = 1
comms = MPI_COMM_NULL
@@ -937,7 +937,7 @@ subroutine esm_init_pelayout(driver, maxthreads, rc)
read(cvalue,*) ntasks
if (ntasks < 0 .or. ntasks > PetCount) then
- write (msgstr, *) "Invalid NTASKS value specified for component: ",namestr, ' ntasks: ',ntasks
+ write (msgstr, *) "Invalid NTASKS value specified for component: ",namestr, ' ntasks: ',ntasks, petcount
call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc)
return
endif
@@ -1156,12 +1156,7 @@ subroutine esm_init_pelayout(driver, maxthreads, rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
enddo
- ! Read in component dependent PIO parameters and initialize
- ! IO systems
- call driver_pio_component_init(driver, size(comps), rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- ! Initialize MCT (this is needed for data models and cice prescribed capability)
call mct_world_init(componentCount+1, GLOBAL_COMM, comms, comps)
@@ -1232,7 +1227,9 @@ subroutine esm_set_single_column_attributes(compname, gcomp, rc)
!-------------------------------------------------------------------------------
rc = ESMF_SUCCESS
+ call shr_log_setLogunit(logunit)
scol_mesh_n = 0
+
! obtain the single column lon and lat
call NUOPC_CompAttributeGet(gcomp, name='scol_lon', value=cvalue, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -1392,11 +1389,12 @@ subroutine esm_set_single_column_attributes(compname, gcomp, rc)
allocate(lonMesh(lsize), latMesh(lsize))
call ESMF_MeshGet(mesh, ownedElemCoords=ownedElemCoords)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
+
+ scol_mesh_n = 0
do n = 1,lsize
lonMesh(n) = ownedElemCoords(2*n-1)
latMesh(n) = ownedElemCoords(2*n)
if (abs(lonMesh(n) - scol_lon) < 1.e-4 .and. abs(latMesh(n) - scol_lat) < 1.e-4) then
- scol_mesh_n = n
scol_mesh_n = n
exit
end if
@@ -1493,7 +1491,7 @@ end subroutine esm_set_single_column_attributes
subroutine esm_finalize(driver, rc)
use ESMF , only : ESMF_GridComp, ESMF_GridCompGet, ESMF_VM, ESMF_VMGet
- use ESMF , only : ESMF_SUCCESS
+ use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO, ESMF_LOGWRITE
use NUOPC , only : NUOPC_CompAttributeGet
use perf_mod , only : t_prf, t_finalizef
@@ -1507,14 +1505,12 @@ subroutine esm_finalize(driver, rc)
logical :: isPresent
type(ESMF_VM) :: vm
integer :: mpicomm
+ character(len=*), parameter :: subname = '(esm_finalize) '
!---------------------------------------
+ call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
rc = ESMF_SUCCESS
-
- if (maintask) then
- write(logunit,*)' SUCCESSFUL TERMINATION OF CESM'
- end if
-
+ call shr_log_setLogunit(logunit)
call ESMF_GridCompGet(driver, vm=vm, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
call ESMF_VMGet(vm, mpiCommunicator=mpicomm, rc=rc)
@@ -1533,6 +1529,11 @@ subroutine esm_finalize(driver, rc)
endif
call t_prf(trim(timing_dir)//'/model_timing'//trim(inst_suffix), mpicom=mpicomm)
+ if (maintask) then
+ write(logunit,*)' SUCCESSFUL TERMINATION OF CESM'
+ end if
+ call ESMF_LogWrite(trim(subname)//": done", ESMF_LOGMSG_INFO)
+
call t_finalizef()
end subroutine esm_finalize
diff --git a/cesm/driver/esm_time_mod.F90 b/cesm/driver/esm_time_mod.F90
index 0c8a6e86c..fc57eaf11 100644
--- a/cesm/driver/esm_time_mod.F90
+++ b/cesm/driver/esm_time_mod.F90
@@ -11,7 +11,8 @@ module esm_time_mod
use ESMF , only : ESMF_TimeInterval, ESMF_TimeIntervalSet, ESMF_TimeIntervalGet
use ESMF , only : ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO, ESMF_FAILURE, ESMF_LOGMSG_ERROR
use ESMF , only : ESMF_VM, ESMF_VMGet, ESMF_VMBroadcast
- use ESMF , only : ESMF_LOGMSG_INFO, ESMF_FAILURE
+ use ESMF , only : ESMF_VMAllReduce, ESMF_REDUCE_MAX
+ use ESMF , only : ESMF_LOGMSG_INFO, ESMF_FAILURE, ESMF_GridCompIsPetLocal
use ESMF , only : operator(<), operator(/=), operator(+)
use ESMF , only : operator(-), operator(*) , operator(>=)
use ESMF , only : operator(<=), operator(>), operator(==)
@@ -62,7 +63,7 @@ subroutine esm_time_clockInit(ensemble_driver, instance_driver, logunit, maintas
! local variables
type(ESMF_Clock) :: clock
- type(ESMF_VM) :: vm
+ type(ESMF_VM) :: vm, envm
type(ESMF_Time) :: StartTime ! Start time
type(ESMF_Time) :: RefTime ! Reference time
type(ESMF_Time) :: CurrTime ! Current time
@@ -100,99 +101,151 @@ subroutine esm_time_clockInit(ensemble_driver, instance_driver, logunit, maintas
character(CL) :: tmpstr ! temporary
character(CS) :: inst_suffix
integer :: tmp(4) ! Array for Broadcast
+ integer :: myid, bcastID(2)
logical :: isPresent
- character(len=*), parameter :: subname = '(esm_time_clockInit): '
+ logical :: inDriver
+ logical, save :: firsttime=.true.
+ character(len=*), parameter :: subname = '('//__FILE__//':esm_time_clockInit) '
!-------------------------------------------------------------------------------
rc = ESMF_SUCCESS
-
- call ESMF_GridCompGet(instance_driver, vm=vm, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
!---------------------------------------------------------------------------
! Determine start time, reference time and current time
!---------------------------------------------------------------------------
- call NUOPC_CompAttributeGet(instance_driver, name="start_ymd", value=cvalue, rc=rc)
+ call NUOPC_CompAttributeGet(ensemble_driver, name="start_ymd", value=cvalue, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
read(cvalue,*) start_ymd
- call NUOPC_CompAttributeGet(instance_driver, name="start_tod", value=cvalue, rc=rc)
+ call NUOPC_CompAttributeGet(ensemble_driver, name="start_tod", value=cvalue, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
read(cvalue,*) start_tod
- call NUOPC_CompAttributeGet(instance_driver, name='read_restart', value=cvalue, rc=rc)
+ !---------------------------------------------------------------------------
+ ! Determine driver clock timestep
+ !---------------------------------------------------------------------------
+
+ call NUOPC_CompAttributeGet(ensemble_driver, name="atm_cpl_dt", value=cvalue, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) read_restart
+ read(cvalue,*) atm_cpl_dt
- if (read_restart) then
+ call NUOPC_CompAttributeGet(ensemble_driver, name="lnd_cpl_dt", value=cvalue, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) lnd_cpl_dt
- call NUOPC_CompAttributeGet(instance_driver, name='drv_restart_pointer', value=restart_file, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ call NUOPC_CompAttributeGet(ensemble_driver, name="ice_cpl_dt", value=cvalue, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) ice_cpl_dt
- if (trim(restart_file) /= 'none') then
+ call NUOPC_CompAttributeGet(ensemble_driver, name="ocn_cpl_dt", value=cvalue, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) ocn_cpl_dt
- call NUOPC_CompAttributeGet(instance_driver, name="inst_suffix", isPresent=isPresent, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- if(isPresent) then
- call NUOPC_CompAttributeGet(instance_driver, name="inst_suffix", value=inst_suffix, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- else
- inst_suffix = ""
- endif
+ call NUOPC_CompAttributeGet(ensemble_driver, name="glc_cpl_dt", value=cvalue, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) glc_cpl_dt
- restart_pfile = trim(restart_file)//inst_suffix
-
- if (maintask) then
- call ESMF_LogWrite(trim(subname)//" read rpointer file = "//trim(restart_pfile), &
- ESMF_LOGMSG_INFO)
- open(newunit=unitn, file=restart_pfile, form='FORMATTED', status='old',iostat=ierr)
- if (ierr < 0) then
- rc = ESMF_FAILURE
- call ESMF_LogWrite(trim(subname)//' ERROR rpointer file open returns error', &
- ESMF_LOGMSG_ERROR, line=__LINE__, file=__FILE__)
- return
- end if
- read(unitn,'(a)', iostat=ierr) restart_file
- if (ierr < 0) then
- rc = ESMF_FAILURE
- call ESMF_LogWrite(trim(subname)//' ERROR rpointer file read returns error', &
- ESMF_LOGMSG_INFO, line=__LINE__, file=__FILE__)
- return
- end if
- close(unitn)
- if (maintask) then
- write(logunit,'(a)') trim(subname)//" reading driver restart from file = "//trim(restart_file)
- end if
- call esm_time_read_restart(restart_file, start_ymd, start_tod, curr_ymd, curr_tod, rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ call NUOPC_CompAttributeGet(ensemble_driver, name="rof_cpl_dt", value=cvalue, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) rof_cpl_dt
- tmp(1) = start_ymd ; tmp(2) = start_tod
- tmp(3) = curr_ymd ; tmp(4) = curr_tod
- endif
+ call NUOPC_CompAttributeGet(ensemble_driver, name="wav_cpl_dt", value=cvalue, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) wav_cpl_dt
- call ESMF_VMBroadcast(vm, tmp, 4, 0, rc=rc)
+ dtime_drv = minval((/atm_cpl_dt, lnd_cpl_dt, ocn_cpl_dt, ice_cpl_dt, glc_cpl_dt, rof_cpl_dt, wav_cpl_dt/))
+ if(maintask) then
+ write(tmpstr,'(i10)') dtime_drv
+ call ESMF_LogWrite(trim(subname)//': driver time interval is : '// trim(tmpstr), ESMF_LOGMSG_INFO, rc=rc)
+ write(logunit,*) trim(subname)//': driver time interval is : '// trim(tmpstr)
+ endif
+ call ESMF_GridCompGet(ensemble_driver, vm=envm, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+
+ call ESMF_VMGet(envm, localPet=myid, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ indriver = ESMF_GridCompIsPetLocal(instance_driver, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+
+ if(indriver) then
+ call ESMF_GridCompGet(instance_driver, vm=vm, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ call NUOPC_CompAttributeGet(instance_driver, name='read_restart', value=cvalue, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ read(cvalue,*) read_restart
+
+ if (read_restart) then
+
+ call NUOPC_CompAttributeGet(instance_driver, name='drv_restart_pointer', value=restart_file, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
- start_ymd = tmp(1) ; start_tod = tmp(2)
- curr_ymd = tmp(3) ; curr_tod = tmp(4)
- else
+ if (trim(restart_file) /= 'none') then
- if (maintask) then
- write(logunit,*) ' NOTE: the current compset has no mediator - which provides the clock restart information'
- write(logunit,*) ' In this case the restarts are handled solely by the component being used and'
- write(logunit,*) ' and the driver clock will always be starting from the initial date on restart'
- end if
- curr_ymd = start_ymd
- curr_tod = start_tod
+ call NUOPC_CompAttributeGet(instance_driver, name="inst_suffix", isPresent=isPresent, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ if(isPresent) then
+ call NUOPC_CompAttributeGet(instance_driver, name="inst_suffix", value=inst_suffix, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ else
+ inst_suffix = ""
+ endif
- end if
+ restart_pfile = trim(restart_file)//inst_suffix
+ if (maintask) then
+ call ESMF_LogWrite(trim(subname)//" read rpointer file = "//trim(restart_pfile), &
+ ESMF_LOGMSG_INFO)
+ open(newunit=unitn, file=restart_pfile, form='FORMATTED', status='old',iostat=ierr)
+ if (ierr < 0) then
+ rc = ESMF_FAILURE
+ call ESMF_LogWrite(trim(subname)//' ERROR rpointer file open returns error', &
+ ESMF_LOGMSG_ERROR, line=__LINE__, file=__FILE__)
+ return
+ end if
+ read(unitn,'(a)', iostat=ierr) restart_file
+ if (ierr < 0) then
+ rc = ESMF_FAILURE
+ call ESMF_LogWrite(trim(subname)//' ERROR rpointer file read returns error', &
+ ESMF_LOGMSG_INFO, line=__LINE__, file=__FILE__)
+ return
+ end if
+ close(unitn)
+ if (maintask) then
+ write(logunit,'(a)') trim(subname)//" reading driver restart from file = "//trim(restart_file)
+ end if
+ call esm_time_read_restart(restart_file, start_ymd, start_tod, curr_ymd, curr_tod, rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ endif
+ else
+ if(maintask) then
+ write(logunit,*) ' NOTE: the current compset has no mediator - which provides the clock restart information'
+ write(logunit,*) ' In this case the restarts are handled solely by the component being used and'
+ write(logunit,*) ' and the driver clock will always be starting from the initial date on restart'
+ end if
+ curr_ymd = start_ymd
+ curr_tod = start_tod
+ endif
+ else
+ curr_ymd = start_ymd
+ curr_tod = start_tod
+ end if ! end if read_restart
+ endif
+ if(maintask) then
+ bcastID(1) = myid
+ tmp(1) = start_ymd ; tmp(2) = start_tod
+ tmp(3) = curr_ymd ; tmp(4) = curr_tod
else
+ bcastID(1) = 0
+ tmp = 0
+ endif
+ call ESMF_VMAllReduce(envm, bcastID(1:1), bcastID(2:2), 1, ESMF_REDUCE_MAX,rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
- curr_ymd = start_ymd
- curr_tod = start_tod
-
- end if ! end if read_restart
+ call ESMF_VMBroadcast(envm, tmp, 4, bcastID(2), rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ start_ymd = tmp(1) ; start_tod = tmp(2)
+ curr_ymd = tmp(3) ; curr_tod = tmp(4)
! Determine start time (THE FOLLOWING ASSUMES THAT THE DEFAULT CALENDAR IS SET in the driver)
@@ -222,7 +275,6 @@ subroutine esm_time_clockInit(ensemble_driver, instance_driver, logunit, maintas
call ESMF_LogWrite(trim(subname)//': driver curr_tod: '// trim(tmpstr), ESMF_LOGMSG_INFO)
write(logunit,*) trim(subname)//': driver curr_tod: '// trim(tmpstr)
endif
-
! Set reference time - HARD-CODED TO START TIME
ref_ymd = start_ymd
ref_tod = start_tod
@@ -230,48 +282,7 @@ subroutine esm_time_clockInit(ensemble_driver, instance_driver, logunit, maintas
call ESMF_TimeSet( RefTime, yy=yr, mm=mon, dd=day, s=ref_tod, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
- !---------------------------------------------------------------------------
- ! Determine driver clock timestep
- !---------------------------------------------------------------------------
-
- call NUOPC_CompAttributeGet(instance_driver, name="atm_cpl_dt", value=cvalue, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) atm_cpl_dt
-
- call NUOPC_CompAttributeGet(instance_driver, name="lnd_cpl_dt", value=cvalue, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) lnd_cpl_dt
-
- call NUOPC_CompAttributeGet(instance_driver, name="ice_cpl_dt", value=cvalue, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) ice_cpl_dt
-
- call NUOPC_CompAttributeGet(instance_driver, name="ocn_cpl_dt", value=cvalue, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) ocn_cpl_dt
-
- call NUOPC_CompAttributeGet(instance_driver, name="glc_cpl_dt", value=cvalue, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) glc_cpl_dt
-
- call NUOPC_CompAttributeGet(instance_driver, name="rof_cpl_dt", value=cvalue, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) rof_cpl_dt
-
- call NUOPC_CompAttributeGet(instance_driver, name="wav_cpl_dt", value=cvalue, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) wav_cpl_dt
- call NUOPC_CompAttributeGet(instance_driver, name="glc_avg_period", value=glc_avg_period, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
- read(cvalue,*) glc_avg_period
-
- dtime_drv = minval((/atm_cpl_dt, lnd_cpl_dt, ocn_cpl_dt, ice_cpl_dt, glc_cpl_dt, rof_cpl_dt, wav_cpl_dt/))
- if(maintask) then
- write(tmpstr,'(i10)') dtime_drv
- call ESMF_LogWrite(trim(subname)//': driver time interval is : '// trim(tmpstr), ESMF_LOGMSG_INFO, rc=rc)
- write(logunit,*) trim(subname)//': driver time interval is : '// trim(tmpstr)
- endif
call ESMF_TimeIntervalSet( TimeStep, s=dtime_drv, rc=rc )
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -293,20 +304,22 @@ subroutine esm_time_clockInit(ensemble_driver, instance_driver, logunit, maintas
if (ChkErr(rc,__LINE__,u_FILE_u)) return
end do
- ! Set the ensemble driver gridded component clock to the created clock
- call ESMF_GridCompSet(instance_driver, clock=clock, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ ! Set the driver gridded component clock to the created clock
+ if (indriver) then
+ call ESMF_GridCompSet(instance_driver, clock=clock, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ endif
! Set driver clock stop time
- call NUOPC_CompAttributeGet(instance_driver, name="stop_option", value=stop_option, rc=rc)
+ call NUOPC_CompAttributeGet(ensemble_driver, name="stop_option", value=stop_option, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
- call NUOPC_CompAttributeGet(instance_driver, name="stop_n", value=cvalue, rc=rc)
+ call NUOPC_CompAttributeGet(ensemble_driver, name="stop_n", value=cvalue, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
read(cvalue,*) stop_n
- call NUOPC_CompAttributeGet(instance_driver, name="stop_ymd", value=cvalue, rc=rc)
+ call NUOPC_CompAttributeGet(ensemble_driver, name="stop_ymd", value=cvalue, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
read(cvalue,*) stop_ymd
- call NUOPC_CompAttributeGet(instance_driver, name="stop_tod", value=cvalue, rc=rc)
+ call NUOPC_CompAttributeGet(ensemble_driver, name="stop_tod", value=cvalue, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
read(cvalue,*) stop_tod
if ( stop_ymd < 0) then
@@ -341,17 +354,17 @@ subroutine esm_time_clockInit(ensemble_driver, instance_driver, logunit, maintas
!---------------------------------------------------------------------------
! Create the ensemble driver clock
- ! TODO: this is done repeatedly - but only needs to be done the first time this is called
!---------------------------------------------------------------------------
+ if(firsttime) then
+ TimeStep = StopTime - ClockTime
+ clock = ESMF_ClockCreate(TimeStep, ClockTime, StopTime=StopTime, &
+ refTime=RefTime, name='ESMF ensemble Driver Clock', rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
- TimeStep = StopTime - ClockTime
- clock = ESMF_ClockCreate(TimeStep, ClockTime, StopTime=StopTime, &
- refTime=RefTime, name='ESMF ensemble Driver Clock', rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
-
- call ESMF_GridCompSet(ensemble_driver, clock=clock, rc=rc)
- if (ChkErr(rc,__LINE__,u_FILE_u)) return
-
+ call ESMF_GridCompSet(ensemble_driver, clock=clock, rc=rc)
+ if (ChkErr(rc,__LINE__,u_FILE_u)) return
+ firsttime = .false.
+ endif
end subroutine esm_time_clockInit
!===============================================================================
diff --git a/cesm/nuopc_cap_share/driver_pio_mod.F90 b/cesm/nuopc_cap_share/driver_pio_mod.F90
index 43d913c6d..ef92bb47a 100644
--- a/cesm/nuopc_cap_share/driver_pio_mod.F90
+++ b/cesm/nuopc_cap_share/driver_pio_mod.F90
@@ -1,9 +1,12 @@
module driver_pio_mod
- use pio
+ use pio , only : pio_offset_kind, pio_rearr_opt_t, PIO_REARR_COMM_UNLIMITED_PEND_REQ
+ use pio , only : pio_iotype_netcdf, pio_iotype_pnetcdf, pio_iotype_netcdf4c, pio_iotype_netcdf4p
+ use pio , only : iosystem_desc_t, PIO_64BIT_DATA, PIO_64BIT_OFFSET, PIO_REARR_COMM_COLL
+ use pio , only : PIO_REARR_COMM_P2P, pio_init, pio_set_log_level
+ use pio , only : pio_set_blocksize, pio_set_buffer_size_limit, pio_finalize
use shr_pio_mod, only : io_compname, pio_comp_settings, iosystems, io_compid, shr_pio_getindex
use shr_kind_mod, only : CS=>shr_kind_CS, shr_kind_cl, shr_kind_in
- use shr_log_mod, only : shr_log_unit
- use shr_mpi_mod, only : shr_mpi_bcast, shr_mpi_chkerr
+ use shr_log_mod, only : shr_log_getLogUnit
use shr_sys_mod, only : shr_sys_abort
#ifndef NO_MPI2
use mpi, only : mpi_comm_null, mpi_comm_world, mpi_finalize
@@ -17,14 +20,14 @@ module driver_pio_mod
public :: driver_pio_init
public :: driver_pio_component_init
public :: driver_pio_finalize
- public :: driver_pio_log_comp_settings
+ private :: driver_pio_log_comp_settings
integer :: io_comm
integer :: pio_debug_level=0, pio_blocksize=0
integer(kind=pio_offset_kind) :: pio_buffer_size_limit=-1
type(pio_rearr_opt_t) :: pio_rearr_opts
- logical, allocatable :: pio_async_interface(:)
+ logical :: pio_async_interface
integer :: total_comps
logical :: maintask
@@ -62,11 +65,13 @@ subroutine driver_pio_init(driver, rc)
character(len=shr_kind_cl) :: nlfilename, cname
integer :: ret
integer :: localPet
+ integer :: logunit
character(len=CS) :: pio_rearr_comm_type, pio_rearr_comm_fcd
character(CS) :: msgstr
character(*), parameter :: subName = '(driver_pio_init) '
-
+
+ call shr_log_getLogUnit(logunit)
call ESMF_GridCompGet(driver, vm=vm, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
@@ -80,7 +85,7 @@ subroutine driver_pio_init(driver, rc)
! 0 is a valid value of pio_buffer_size_limit
if(pio_buffer_size_limit>=0) then
- if(maintask) write(shr_log_unit,*) 'Setting pio_buffer_size_limit : ',pio_buffer_size_limit
+ if(maintask) write(logunit,*) 'Setting pio_buffer_size_limit : ',pio_buffer_size_limit
call pio_set_buffer_size_limit(pio_buffer_size_limit)
endif
@@ -89,7 +94,7 @@ subroutine driver_pio_init(driver, rc)
read(cname, *) pio_blocksize
if(pio_blocksize>0) then
- if(maintask) write(shr_log_unit,*) 'Setting pio_blocksize : ',pio_blocksize
+ if(maintask) write(logunit,*) 'Setting pio_blocksize : ',pio_blocksize
call pio_set_blocksize(pio_blocksize)
endif
@@ -98,7 +103,7 @@ subroutine driver_pio_init(driver, rc)
read(cname, *) pio_debug_level
if(pio_debug_level > 0) then
- if(maintask) write(shr_log_unit,*) 'Setting pio_debug_level : ',pio_debug_level
+ if(maintask) write(logunit,*) 'Setting pio_debug_level : ',pio_debug_level
ret = pio_set_log_level(pio_debug_level)
endif
@@ -120,22 +125,22 @@ subroutine driver_pio_init(driver, rc)
call NUOPC_CompAttributeGet(driver, name="pio_rearr_comm_enable_hs_comp2io", value=cname, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
- pio_rearr_opts%comm_fc_opts_comp2io%enable_hs = (trim(cname) .eq. '.true.')
+ pio_rearr_opts%comm_fc_opts_comp2io%enable_hs = logical((trim(cname) .eq. '.true.'), kind=1)
call NUOPC_CompAttributeGet(driver, name="pio_rearr_comm_enable_hs_io2comp", value=cname, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
- pio_rearr_opts%comm_fc_opts_io2comp%enable_hs = (trim(cname) .eq. '.true.')
+ pio_rearr_opts%comm_fc_opts_io2comp%enable_hs = logical((trim(cname) .eq. '.true.'), kind=1)
call NUOPC_CompAttributeGet(driver, name="pio_rearr_comm_enable_isend_comp2io", value=cname, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
- pio_rearr_opts%comm_fc_opts_comp2io%enable_isend = (trim(cname) .eq. '.true.')
+ pio_rearr_opts%comm_fc_opts_comp2io%enable_isend = logical((trim(cname) .eq. '.true.'), kind=1)
call NUOPC_CompAttributeGet(driver, name="pio_rearr_comm_enable_isend_io2comp", value=cname, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
- pio_rearr_opts%comm_fc_opts_io2comp%enable_isend = (trim(cname) .eq. '.true.')
+ pio_rearr_opts%comm_fc_opts_io2comp%enable_isend = logical((trim(cname) .eq. '.true.'), kind=1)
call NUOPC_CompAttributeGet(driver, name="pio_rearr_comm_max_pend_req_comp2io", value=cname, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
@@ -147,98 +152,166 @@ subroutine driver_pio_init(driver, rc)
if(maintask) then
! Log the rearranger options
- write(shr_log_unit, *) "PIO rearranger options:"
- write(shr_log_unit, *) " comm type = ", pio_rearr_opts%comm_type, " (",trim(pio_rearr_comm_type),")"
- write(shr_log_unit, *) " comm fcd = ", pio_rearr_opts%fcd, " (",trim(pio_rearr_comm_fcd),")"
+ write(logunit, *) "PIO rearranger options:"
+ write(logunit, *) " comm type = ", pio_rearr_opts%comm_type, " (",trim(pio_rearr_comm_type),")"
+ write(logunit, *) " comm fcd = ", pio_rearr_opts%fcd, " (",trim(pio_rearr_comm_fcd),")"
if(pio_rearr_opts%comm_fc_opts_comp2io%max_pend_req == PIO_REARR_COMM_UNLIMITED_PEND_REQ) then
- write(shr_log_unit, *) " max pend req (comp2io) = PIO_REARR_COMM_UNLIMITED_PEND_REQ (-1)"
+ write(logunit, *) " max pend req (comp2io) = PIO_REARR_COMM_UNLIMITED_PEND_REQ (-1)"
else
- write(shr_log_unit, *) " max pend req (comp2io) = ", pio_rearr_opts%comm_fc_opts_comp2io%max_pend_req
+ write(logunit, *) " max pend req (comp2io) = ", pio_rearr_opts%comm_fc_opts_comp2io%max_pend_req
end if
- write(shr_log_unit, *) " enable_hs (comp2io) = ", pio_rearr_opts%comm_fc_opts_comp2io%enable_hs
- write(shr_log_unit, *) " enable_isend (comp2io) = ", pio_rearr_opts%comm_fc_opts_comp2io%enable_isend
+ write(logunit, *) " enable_hs (comp2io) = ", pio_rearr_opts%comm_fc_opts_comp2io%enable_hs
+ write(logunit, *) " enable_isend (comp2io) = ", pio_rearr_opts%comm_fc_opts_comp2io%enable_isend
if(pio_rearr_opts%comm_fc_opts_io2comp%max_pend_req == PIO_REARR_COMM_UNLIMITED_PEND_REQ) then
- write(shr_log_unit, *) " max pend req (io2comp) = PIO_REARR_COMM_UNLIMITED_PEND_REQ (-1)"
+ write(logunit, *) " max pend req (io2comp) = PIO_REARR_COMM_UNLIMITED_PEND_REQ (-1)"
else
- write(shr_log_unit, *) " max pend req (io2comp) = ", pio_rearr_opts%comm_fc_opts_io2comp%max_pend_req
+ write(logunit, *) " max pend req (io2comp) = ", pio_rearr_opts%comm_fc_opts_io2comp%max_pend_req
end if
- write(shr_log_unit, *) " enable_hs (io2comp) = ", pio_rearr_opts%comm_fc_opts_io2comp%enable_hs
- write(shr_log_unit, *) " enable_isend (io2comp) = ", pio_rearr_opts%comm_fc_opts_io2comp%enable_isend
+ write(logunit, *) " enable_hs (io2comp) = ", pio_rearr_opts%comm_fc_opts_io2comp%enable_hs
+ write(logunit, *) " enable_isend (io2comp) = ", pio_rearr_opts%comm_fc_opts_io2comp%enable_isend
end if
end subroutine driver_pio_init
- subroutine driver_pio_component_init(driver, ncomps, rc)
+ subroutine driver_pio_component_init(driver, Inst_comm, asyncio_petlist, rc)
use ESMF, only : ESMF_GridComp, ESMF_LogSetError, ESMF_RC_NOT_VALID, ESMF_GridCompIsCreated, ESMF_VM, ESMF_VMGet
- use ESMF, only : ESMF_GridCompGet, ESMF_GridCompIsPetLocal, ESMF_VMIsCreated
+ use ESMF, only : ESMF_GridCompGet, ESMF_GridCompIsPetLocal, ESMF_VMIsCreated, ESMF_Finalize, ESMF_PtrInt1D
+ use ESMF, only : ESMF_LOGMSG_INFO, ESMF_LOGWRITE
use NUOPC, only : NUOPC_CompAttributeGet, NUOPC_CompAttributeSet, NUOPC_CompAttributeAdd
use NUOPC_Driver, only : NUOPC_DriverGetComp
+ use mpi, only : MPI_INTEGER, MPI_MAX, MPI_IN_PLACE, MPI_LOR, MPI_LOGICAL
type(ESMF_GridComp) :: driver
- type(ESMF_VM) :: vm
- integer, intent(in) :: ncomps
+ integer, intent(in) :: Inst_comm ! The communicator associated with the ensemble_driver
+ integer, intent(in) :: asyncio_petlist(:)
integer, intent(out) :: rc
+ type(ESMF_VM) :: vm
integer :: i, npets, default_stride
- integer :: j
+ integer :: j, myid
+ integer :: k
integer :: comp_comm, comp_rank
+ integer, allocatable :: procs_per_comp(:), async_procs_per_comp(:)
+ integer, allocatable :: io_proc_list(:), asyncio_tasks(:), comp_proc_list(:,:)
+
type(ESMF_GridComp), pointer :: gcomp(:)
character(CS) :: cval
character(CS) :: msgstr
integer :: do_async_init
+ integer :: totalpes
+ integer :: asyncio_ntasks
+ integer :: asyncio_stride
+ integer :: pecnt
+ integer :: ierr
+ integer :: iocomm
+ integer :: pp
+ integer :: async_rearr
+ integer :: maxprocspercomp, driver_myid
+ integer, allocatable :: driverpetlist(:)
+ integer, allocatable :: asyncio_comp_comm(:)
+ integer :: logunit
+ integer :: ioproc
+ integer :: n
+ logical :: asyncio_task
+ logical, allocatable :: petlocal(:)
+ type(ESMF_PtrInt1D), pointer :: petLists(:)
type(iosystem_desc_t), allocatable :: async_iosystems(:)
+ character(len=*), parameter :: subname = '('//__FILE__//':shr_pio_component_init)'
- allocate(pio_comp_settings(ncomps))
- allocate(gcomp(ncomps))
+ asyncio_ntasks = size(asyncio_petlist)
- allocate(io_compid(ncomps))
- allocate(io_compname(ncomps))
- allocate(iosystems(ncomps))
+ call shr_log_getLogUnit(logunit)
+ call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
- allocate(pio_async_interface(ncomps))
+ call MPI_Comm_rank(Inst_comm, myid, rc)
+ call MPI_Comm_size(Inst_comm, totalpes, rc)
+ asyncio_task=.false.
+ do i=1,asyncio_ntasks
+ ! asyncio_petlist is in
+ if(modulo(asyncio_petlist(i), totalpes) == myid) then
+ asyncio_task = .true.
+ exit
+ endif
+ enddo
nullify(gcomp)
- do_async_init = 0
+ nullify(petLists)
+ if (.not. asyncio_task) then
+ call ESMF_GridCompGet(gridcomp=driver, vm=vm, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+
+ call NUOPC_DriverGetComp(driver, compList=gcomp, petLists=petLists, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_VMGet(vm, localPet=driver_myid, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ endif
+ if(associated(gcomp)) then
+ total_comps = size(gcomp)
+ else
+ total_comps = 0
+ endif
- call NUOPC_DriverGetComp(driver, compList=gcomp, rc=rc)
+ call ESMF_LogWrite(trim(subname)//": share total_comps and driverpecount", ESMF_LOGMSG_INFO)
if (chkerr(rc,__LINE__,u_FILE_u)) return
+ if(totalpes > 1) then
+ call MPI_AllReduce(MPI_IN_PLACE, total_comps, 1, MPI_INTEGER, &
+ MPI_MAX, Inst_comm, rc)
+ endif
+
+ allocate(pio_comp_settings(total_comps))
+ allocate(procs_per_comp(total_comps))
+ allocate(io_compid(total_comps))
+ allocate(io_compname(total_comps))
+ allocate(iosystems(total_comps))
+ allocate(petlocal(total_comps))
+ do_async_init = 0
+ procs_per_comp = 0
- total_comps = size(gcomp)
-
do i=1,total_comps
- io_compid(i) = i+1
+ if(associated(gcomp)) then
+ petlocal(i) = ESMF_GridCompIsPetLocal(gcomp(i), rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
- if (ESMF_GridCompIsPetLocal(gcomp(i), rc=rc)) then
- call ESMF_GridCompGet(gcomp(i), vm=vm, name=cval, rc=rc)
+ call NUOPC_CompAttributeGet(gcomp(i), name="pio_async_interface", value=cval, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
+ pio_comp_settings(i)%pio_async_interface = (trim(cval) == '.true.')
- io_compname(i) = trim(cval)
-
+ call NUOPC_CompAttributeGet(gcomp(i), name="pio_rearranger", value=cval, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ read(cval, *) pio_comp_settings(i)%pio_rearranger
+ else
+ petlocal(i) = .false.
+ endif
+ pio_comp_settings(i)%pio_async_interface = .false.
+ io_compid(i) = i+1
+
+ if (petlocal(i)) then
call NUOPC_CompAttributeAdd(gcomp(i), attrList=(/'MCTID'/), rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
-
write(cval, *) io_compid(i)
call NUOPC_CompAttributeSet(gcomp(i), name="MCTID", value=trim(cval), rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
-
- call ESMF_VMGet(vm, mpiCommunicator=comp_comm, rc=rc)
+
+ call ESMF_GridCompGet(gcomp(i), vm=vm, name=cval, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_LogWrite(trim(subname)//": initialize component: "//trim(cval), ESMF_LOGMSG_INFO)
+ io_compname(i) = trim(cval)
- if(comp_comm .ne. MPI_COMM_NULL) then
- call ESMF_VMGet(vm, petCount=npets, localPet=comp_rank, ssiLocalPetCount=default_stride, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_VMGet(vm, mpiCommunicator=comp_comm, localPet=comp_rank, petCount=npets, &
+ ssiLocalPetCount=default_stride, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ procs_per_comp(i) = npets
+
+ if(.not. pio_comp_settings(i)%pio_async_interface) then
call NUOPC_CompAttributeGet(gcomp(i), name="pio_stride", value=cval, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
read(cval, *) pio_comp_settings(i)%pio_stride
if(pio_comp_settings(i)%pio_stride <= 0 .or. pio_comp_settings(i)%pio_stride > npets) then
pio_comp_settings(i)%pio_stride = min(npets, default_stride)
endif
-
- call NUOPC_CompAttributeGet(gcomp(i), name="pio_rearranger", value=cval, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- read(cval, *) pio_comp_settings(i)%pio_rearranger
-
+
call NUOPC_CompAttributeGet(gcomp(i), name="pio_numiotasks", value=cval, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
read(cval, *) pio_comp_settings(i)%pio_numiotasks
@@ -247,84 +320,167 @@ subroutine driver_pio_component_init(driver, ncomps, rc)
pio_comp_settings(i)%pio_numiotasks = max(1,npets/pio_comp_settings(i)%pio_stride)
endif
+
call NUOPC_CompAttributeGet(gcomp(i), name="pio_root", value=cval, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
read(cval, *) pio_comp_settings(i)%pio_root
-
+
if(pio_comp_settings(i)%pio_root < 0 .or. pio_comp_settings(i)%pio_root > npets) then
pio_comp_settings(i)%pio_root = 0
endif
+ endif
+
+ call NUOPC_CompAttributeGet(gcomp(i), name="pio_typename", value=cval, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
- call NUOPC_CompAttributeGet(gcomp(i), name="pio_typename", value=cval, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
-
- select case (trim(cval))
- case ('pnetcdf')
- pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_PNETCDF
- case ('netcdf')
- pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_NETCDF
- case ('netcdf4p')
- pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_NETCDF4P
- case ('netcdf4c')
- pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_NETCDF4C
- case DEFAULT
- write (msgstr, *) "Invalid PIO_TYPENAME Setting for component ", trim(cval)
- call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc)
- return
- end select
-
- call NUOPC_CompAttributeGet(gcomp(i), name="pio_async_interface", value=cval, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- pio_async_interface(i) = (trim(cval) == '.true.')
-
- call NUOPC_CompAttributeGet(gcomp(i), name="pio_netcdf_format", value=cval, rc=rc)
- if (chkerr(rc,__LINE__,u_FILE_u)) return
- call driver_pio_getioformatfromname(cval, pio_comp_settings(i)%pio_netcdf_ioformat, PIO_64BIT_DATA)
-
- if (pio_async_interface(i)) then
- do_async_init = do_async_init + 1
- else
- if(pio_rearr_opts%comm_fc_opts_io2comp%max_pend_req < PIO_REARR_COMM_UNLIMITED_PEND_REQ) then
- pio_rearr_opts%comm_fc_opts_io2comp%max_pend_req = pio_comp_settings(i)%pio_numiotasks
- endif
- if(pio_rearr_opts%comm_fc_opts_comp2io%max_pend_req < PIO_REARR_COMM_UNLIMITED_PEND_REQ) then
- pio_rearr_opts%comm_fc_opts_comp2io%max_pend_req = pio_comp_settings(i)%pio_numiotasks
- endif
- call pio_init(comp_rank ,comp_comm ,pio_comp_settings(i)%pio_numiotasks, 0, pio_comp_settings(i)%pio_stride, &
- pio_comp_settings(i)%pio_rearranger, iosystems(i), pio_comp_settings(i)%pio_root, &
- pio_rearr_opts)
+ select case (trim(cval))
+ case ('pnetcdf')
+ pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_PNETCDF
+ case ('netcdf')
+ pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_NETCDF
+ case ('netcdf4p')
+ pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_NETCDF4P
+ case ('netcdf4c')
+ pio_comp_settings(i)%pio_iotype = PIO_IOTYPE_NETCDF4C
+ case DEFAULT
+ write (msgstr, *) "Invalid PIO_TYPENAME Setting for component ", trim(cval)
+ call ESMF_LogSetError(ESMF_RC_NOT_VALID, msg=msgstr, line=__LINE__, file=__FILE__, rcToReturn=rc)
+ return
+ end select
+
+ call NUOPC_CompAttributeGet(gcomp(i), name="pio_netcdf_format", value=cval, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call driver_pio_getioformatfromname(cval, pio_comp_settings(i)%pio_netcdf_ioformat, PIO_64BIT_DATA)
+
+ if (.not. pio_comp_settings(i)%pio_async_interface) then
+ if(pio_rearr_opts%comm_fc_opts_io2comp%max_pend_req < PIO_REARR_COMM_UNLIMITED_PEND_REQ) then
+ pio_rearr_opts%comm_fc_opts_io2comp%max_pend_req = pio_comp_settings(i)%pio_numiotasks
+ endif
+ if(pio_rearr_opts%comm_fc_opts_comp2io%max_pend_req < PIO_REARR_COMM_UNLIMITED_PEND_REQ) then
+ pio_rearr_opts%comm_fc_opts_comp2io%max_pend_req = pio_comp_settings(i)%pio_numiotasks
endif
+
+ call pio_init(comp_rank ,comp_comm ,pio_comp_settings(i)%pio_numiotasks, 0, pio_comp_settings(i)%pio_stride, &
+ pio_comp_settings(i)%pio_rearranger, iosystems(i), pio_comp_settings(i)%pio_root, &
+ pio_rearr_opts)
endif
+ ! Write the PIO settings to the beggining of each component log
+ if(comp_rank == 0) call driver_pio_log_comp_settings(gcomp(i), rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+
endif
enddo
+
+ call ESMF_LogWrite(trim(subname)//": check for async", ESMF_LOGMSG_INFO)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ do i=1,total_comps
+ call MPI_AllReduce(MPI_IN_PLACE, pio_comp_settings(i)%pio_async_interface, 1, MPI_LOGICAL, &
+ MPI_LOR, Inst_comm, rc)
+ if(pio_comp_settings(i)%pio_async_interface) then
+ do_async_init = do_async_init + 1
+ endif
+ enddo
+
+!
+! Get the PET list for each component using async IO
+!
+
+ call MPI_Allreduce(MPI_IN_PLACE, do_async_init, 1, MPI_INTEGER, MPI_MAX, Inst_comm, ierr)
+ call MPI_Allreduce(MPI_IN_PLACE, procs_per_comp, total_comps, MPI_INTEGER, MPI_MAX, Inst_comm, ierr)
if (do_async_init > 0) then
+ maxprocspercomp = 0
+ do i=1,total_comps
+ if(procs_per_comp(i) > maxprocspercomp) maxprocspercomp = procs_per_comp(i)
+ enddo
+ call MPI_AllReduce(MPI_IN_PLACE, maxprocspercomp, 1, MPI_INTEGER, &
+ MPI_MAX, Inst_comm, rc)
+
+ allocate(asyncio_comp_comm(do_async_init))
+ allocate(comp_proc_list(maxprocspercomp, do_async_init))
+ j = 1
+ k = 1
+ comp_proc_list = -1
+ if(.not. asyncio_task) then
+ do i=1,total_comps
+ if(pio_comp_settings(i)%pio_async_interface) then
+ comp_proc_list(1:procs_per_comp(i), j) = petLists(i)%ptr
+ ! IO tasks are not in the driver comp so we need to correct the comp_proc_list
+ do k=1,size(asyncio_petlist)
+ ioproc = asyncio_petlist(k)
+ do n=1,procs_per_comp(i)
+ if(petLists(i)%ptr(n) >= (ioproc-k+1)) comp_proc_list(n,j) = comp_proc_list(n,j) + 1
+ enddo
+ enddo
+ j = j+1
+ endif
+! deallocate(petLists(i)%ptr)
+ enddo
+ endif
+ ! Copy comp_proc_list to io tasks
+ do i=1,do_async_init
+ call MPI_AllReduce(MPI_IN_PLACE, comp_proc_list(:,i), maxprocspercomp, MPI_INTEGER, MPI_MAX, Inst_comm, ierr)
+ enddo
+ if(asyncio_ntasks == 0) then
+ call shr_sys_abort(subname//' ERROR: ASYNC IO Requested but no IO PES assigned')
+ endif
+
allocate(async_iosystems(do_async_init))
+ allocate(async_procs_per_comp(do_async_init))
j=1
+ async_rearr = 0
do i=1,total_comps
- if(pio_async_interface(i)) then
- iosystems(i) = async_iosystems(j)
+ if(pio_comp_settings(i)%pio_async_interface) then
+ async_procs_per_comp(j) = procs_per_comp(i)
j = j+1
+ if(.not.asyncio_task) then
+ if(async_rearr == 0) then
+ async_rearr = pio_comp_settings(i)%pio_rearranger
+ elseif(async_rearr .ne. pio_comp_settings(i)%pio_rearranger .and. pio_comp_settings(i)%pio_rearranger > 0) then
+ write(msgstr,*) i,async_rearr,pio_comp_settings(i)%pio_rearranger
+ call shr_sys_abort(subname//' ERROR: all async component rearrangers must match '//msgstr)
+ endif
+ endif
endif
enddo
+ ! IO tasks should not return until the run is completed
+ !ierr = pio_set_log_level(1)
+ call ESMF_LogWrite(trim(subname)//": call async pio_init", ESMF_LOGMSG_INFO)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call MPI_AllReduce(MPI_IN_PLACE, async_rearr, 1, MPI_INTEGER, &
+ MPI_MAX, Inst_comm, rc)
+ call pio_init(async_iosystems, Inst_comm, async_procs_per_comp, &
+ comp_proc_list, asyncio_petlist, &
+ async_rearr, asyncio_comp_comm, io_comm)
+ if(.not. asyncio_task) then
+ j=1
+ do i=1,total_comps
+ if(pio_comp_settings(i)%pio_async_interface) then
+ iosystems(i) = async_iosystems(j)
+ j = j+1
+ endif
+ enddo
+ endif
endif
-
- deallocate(gcomp)
+ call ESMF_LogWrite(trim(subname)//": done", ESMF_LOGMSG_INFO)
+ if(associated(petLists)) deallocate(petLists)
+ if(associated(gcomp)) deallocate(gcomp)
end subroutine driver_pio_component_init
- subroutine driver_pio_log_comp_settings(gcomp, logunit)
- use ESMF, only : ESMF_GridComp, ESMF_GridCompGet
+ subroutine driver_pio_log_comp_settings(gcomp, rc)
+ use ESMF, only : ESMF_GridComp, ESMF_GridCompGet, ESMF_SUCCESS
use NUOPC, only: NUOPC_CompAttributeGet
-
+ use, intrinsic :: iso_fortran_env, only: output_unit
+
type(ESMF_GridComp) :: gcomp
- integer, intent(in) :: logunit
-
+ integer, intent(out) :: rc
integer :: compid
character(len=CS) :: name, cval
integer :: i
- integer :: rc
+ integer :: logunit
logical :: isPresent
+ rc = ESMF_SUCCESS
call ESMF_GridCompGet(gcomp, name=name, rc=rc)
if (chkerr(rc,__LINE__,u_FILE_u)) return
@@ -335,21 +491,29 @@ subroutine driver_pio_log_comp_settings(gcomp, logunit)
read(cval, *) compid
i = shr_pio_getindex(compid)
endif
- write(logunit,*) trim(name),': PIO numiotasks=', pio_comp_settings(i)%pio_numiotasks
-
- write(logunit, *) trim(name), ': PIO stride=',pio_comp_settings(i)%pio_stride
-
- write(logunit, *) trim(name),': PIO rearranger=',pio_comp_settings(i)%pio_rearranger
- write(logunit, *) trim(name),': PIO root=',pio_comp_settings(i)%pio_root
-
+ logunit = 6
+ call NUOPC_CompAttributeGet(gcomp, name="logunit", value=logunit, isPresent=ispresent, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ if(.not. isPresent) then
+ logunit = output_unit
+ if(maintask) write(logunit,*) 'Attribute logunit not set for ',trim(name)
+ endif
+ if(pio_comp_settings(i)%pio_async_interface) then
+ write(logunit,*) trim(name),': using ASYNC IO interface'
+ else
+ write(logunit,*) trim(name),': PIO numiotasks=', pio_comp_settings(i)%pio_numiotasks
+ write(logunit, *) trim(name), ': PIO stride=',pio_comp_settings(i)%pio_stride
+ write(logunit, *) trim(name),': PIO rearranger=',pio_comp_settings(i)%pio_rearranger
+ write(logunit, *) trim(name),': PIO root=',pio_comp_settings(i)%pio_root
+ endif
end subroutine driver_pio_log_comp_settings
!===============================================================================
subroutine driver_pio_finalize( )
integer :: ierr
integer :: i
- do i=1,total_comps
+ do i=1,size(iosystems)
call pio_finalize(iosystems(i), ierr)
end do
@@ -383,6 +547,10 @@ subroutine driver_pio_getiotypefromname(typename, iotype, defaulttype)
integer, intent(out) :: iotype
integer, intent(in) :: defaulttype
+ integer :: logunit
+
+ call shr_log_getLogUnit(logunit)
+
typename = shr_string_toupper(typename)
if ( typename .eq. 'NETCDF' ) then
iotype = pio_iotype_netcdf
@@ -397,7 +565,7 @@ subroutine driver_pio_getiotypefromname(typename, iotype, defaulttype)
else if ( typename .eq. 'DEFAULT') then
iotype = defaulttype
else
- write(shr_log_unit,*) 'driver_pio_mod: WARNING Bad io_type argument - using iotype_netcdf'
+ write(logunit,*) 'driver_pio_mod: WARNING Bad io_type argument - using iotype_netcdf'
iotype=pio_iotype_netcdf
end if
diff --git a/cesm/nuopc_cap_share/nuopc_shr_methods.F90 b/cesm/nuopc_cap_share/nuopc_shr_methods.F90
index 3d50906d7..9062b27f1 100644
--- a/cesm/nuopc_cap_share/nuopc_shr_methods.F90
+++ b/cesm/nuopc_cap_share/nuopc_shr_methods.F90
@@ -130,9 +130,8 @@ subroutine get_component_instance(gcomp, inst_suffix, inst_index, rc)
end subroutine get_component_instance
!===============================================================================
-
subroutine set_component_logging(gcomp, maintask, logunit, shrlogunit, rc)
- use driver_pio_mod, only : driver_pio_log_comp_settings
+ use NUOPC, only: NUOPC_CompAttributeSet, NUOPC_CompAttributeAdd
! input/output variables
type(ESMF_GridComp) :: gcomp
logical, intent(in) :: maintask
@@ -144,8 +143,10 @@ subroutine set_component_logging(gcomp, maintask, logunit, shrlogunit, rc)
character(len=CL) :: diro
character(len=CL) :: logfile
character(len=CL) :: inst_suffix
- integer :: inst_index ! not used here
+ integer :: inst_index ! Not used here
integer :: n
+ character(len=CL) :: name
+ character(len=*), parameter :: subname = "("//__FILE__//": set_component_logging)"
!-----------------------------------------------------------------------
rc = ESMF_SUCCESS
@@ -164,16 +165,23 @@ subroutine set_component_logging(gcomp, maintask, logunit, shrlogunit, rc)
endif
open(newunit=logunit,file=trim(diro)//"/"//trim(logfile))
- ! Write the PIO settings to the beggining of each component log
- call driver_pio_log_comp_settings(gcomp, logunit)
else
logUnit = 6
endif
- shrlogunit = logunit
+
+ call ESMF_GridCompGet(gcomp, name=name, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call ESMF_LogWrite(trim(subname)//": setting logunit for component: "//trim(name), ESMF_LOGMSG_INFO)
+ call NUOPC_CompAttributeAdd(gcomp, (/"logunit"/), rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
+ call NUOPC_CompAttributeSet(gcomp, "logunit", logunit, rc=rc)
+ if (chkerr(rc,__LINE__,u_FILE_u)) return
call shr_log_setLogUnit (logunit)
-
+ ! Still need to set this return value
+ shrlogunit = logunit
+ call ESMF_LogWrite(trim(subname)//": done for component "//trim(name), ESMF_LOGMSG_INFO)
end subroutine set_component_logging
!===============================================================================
diff --git a/cime_config/buildnml b/cime_config/buildnml
index 32d6df1c0..6b76da004 100755
--- a/cime_config/buildnml
+++ b/cime_config/buildnml
@@ -298,8 +298,13 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files):
# --------------------------------
# Determine valid components
valid_comps = []
+ asyncio = False
+
for item in case.get_values("COMP_CLASSES"):
comp = case.get_value("COMP_" + item)
+ if case.get_value(f"PIO_ASYNC_INTERFACE", {"compclass":item}):
+ asyncio = True
+
valid = True
if comp == "s" + item.lower():
# stub comps
@@ -322,6 +327,20 @@ def _create_drv_namelists(case, infile, confdir, nmlgen, files):
valid = False
if valid:
valid_comps.append(item)
+ asyncio_ntasks = case.get_value("PIO_ASYNCIO_NTASKS")
+ asyncio_stride = case.get_value("PIO_ASYNCIO_STRIDE")
+ # If asyncio is enabled make sure that the aysncio values are set
+ # if not enabled then do not pass xml settings to namelists.
+ if asyncio:
+ expect(asyncio_ntasks > 0 and asyncio_stride > 0,
+ "ASYNCIO is enabled but PIO_ASYNCIO_NTASKS={} and PIO_ASYNCIO_STRIDE = {}".
+ format(asyncio_ntasks, asyncio_stride))
+ else:
+ if asyncio_ntasks > 0 or asyncio_stride > 0:
+ logger.warning("ASYNCIO is disabled, ignoring settings for PIO_ASYNCIO_NTASKS={} and PIO_ASYNCIO_STRIDE = {}".
+ format(asyncio_ntasks, asyncio_stride))
+ nmlgen.set_value("pio_asyncio_ntasks", 0)
+ nmlgen.set_value("pio_asyncio_stride", 0)
# Determine if there are any data components in the compset
datamodel_in_compset = False
diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml
index c06f7a7f3..7f9bac96e 100644
--- a/cime_config/config_component.xml
+++ b/cime_config/config_component.xml
@@ -2023,6 +2023,30 @@
pio blocksize for box decompositions
+
+ integer
+ 0
+ run_pio
+ env_mach_pes.xml
+ Task count for asyncronous IO, only valid if PIO_ASYNC_INTERFACE is True
+
+
+
+ integer
+ 0
+ run_pio
+ env_mach_pes.xml
+ Stride of tasks for asyncronous IO, only valid if PIO_ASYNC_INTERFACE is True
+
+
+
+ integer
+ 1
+ run_pio
+ env_mach_pes.xml
+ RootPE of tasks for asyncronous IO, only valid if PIO_ASYNC_INTERFACE is True
+
+
integer
-1
diff --git a/cime_config/namelist_definition_drv.xml b/cime_config/namelist_definition_drv.xml
index ce1ae92ff..8bc022f22 100644
--- a/cime_config/namelist_definition_drv.xml
+++ b/cime_config/namelist_definition_drv.xml
@@ -36,6 +36,42 @@
+
+ integer
+ pio
+ PELAYOUT_attributes
+
+ IO tasks FOR ASYNC IO, only valid if ASYNCIO is true.
+
+
+ $PIO_ASYNCIO_NTASKS
+
+
+
+
+ integer
+ pio
+ PELAYOUT_attributes
+
+ IO task stride FOR ASYNC IO, only valid if ASYNCIO is true.
+
+
+ $PIO_ASYNCIO_STRIDE
+
+
+
+
+ integer
+ pio
+ PELAYOUT_attributes
+
+ IO rootpe task FOR ASYNC IO, only valid if ASYNCIO is true.
+
+
+ $PIO_ASYNCIO_ROOTPE
+
+
+
char
expdef
diff --git a/cime_config/testdefs/testlist_drv.xml b/cime_config/testdefs/testlist_drv.xml
index 7368a1fd2..ec86e5989 100644
--- a/cime_config/testdefs/testlist_drv.xml
+++ b/cime_config/testdefs/testlist_drv.xml
@@ -260,4 +260,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cime_config/testdefs/testmods_dirs/drv/asyncio1node/shell_commands b/cime_config/testdefs/testmods_dirs/drv/asyncio1node/shell_commands
new file mode 100644
index 000000000..70ec80d0e
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/drv/asyncio1node/shell_commands
@@ -0,0 +1,17 @@
+# This will add 4 asyncio tasks on the first node
+./xmlchange PIO_ASYNCIO_ROOTPE=0
+./xmlchange PIO_ASYNCIO_STRIDE=1
+./xmlchange PIO_ASYNCIO_NTASKS=4
+./xmlchange PIO_REARRANGER=2
+./xmlchange PIO_ASYNC_INTERFACE=TRUE
+for comp in ATM OCN LND ICE CPL GLC ROF
+do
+ rootpe=`./xmlquery --value ROOTPE_$comp`
+ let newrootpe=rootpe+4
+ ./xmlchange ROOTPE_$comp=$newrootpe
+done
+comp_ocn=`./xmlquery --value COMP_OCN`
+# MOM ocn has no pio interface
+if [[ "$comp_ocn" == "mom" ]]; then
+ ./xmlchange PIO_ASYNC_INTERFACE_OCN=FALSE;
+fi
diff --git a/cime_config/testdefs/testmods_dirs/drv/asyncio1pernode/shell_commands b/cime_config/testdefs/testmods_dirs/drv/asyncio1pernode/shell_commands
new file mode 100644
index 000000000..05077453c
--- /dev/null
+++ b/cime_config/testdefs/testmods_dirs/drv/asyncio1pernode/shell_commands
@@ -0,0 +1,22 @@
+# This will add one async pio task per node to a test
+# does not work for all cases
+max2() { printf '%d' $(( $1 > $2 ? $1 : $2 )); }
+let totaltasks=0
+./xmlchange --force --force PIO_ASYNC_INTERFACE=TRUE
+for comp in ATM OCN LND ICE CPL GLC ROF
+do
+ ntasks=`./xmlquery --value NTASKS_$comp`
+ rootpe=`./xmlquery --value ROOTPE_$comp`
+ let maxpe=ntasks+rootpe
+ totaltasks=$(( $totaltasks > $maxpe ? $totaltasks : $maxpe ))
+done
+echo "totaltasks is $totaltasks"
+tpn=`./xmlquery --value MAX_MPITASKS_PER_NODE`
+./xmlchange --force --force PIO_ASYNCIO_STRIDE=$tpn
+let piontasks=totaltasks/tpn
+echo "piontasks=$piontasks"
+./xmlchange --force --force PIO_ASYNCIO_NTASKS=$piontasks
+let newntasks=totaltasks-piontasks
+echo "newntasks=$newntasks"
+./xmlchange --force --force NTASKS=$newntasks
+./xmlchange --force --force PIO_REARRANGER=2
diff --git a/mediator/med.F90 b/mediator/med.F90
index 79a43a4c9..e7c6da9d3 100644
--- a/mediator/med.F90
+++ b/mediator/med.F90
@@ -59,10 +59,10 @@ module MED
public SetServices
public SetVM
private InitializeP0
- private InitializeIPDv03p1 ! advertise fields
- private InitializeIPDv03p3 ! realize connected Fields with transfer action "provide"
- private InitializeIPDv03p4 ! optionally modify the decomp/distr of transferred Grid/Mesh
- private InitializeIPDv03p5 ! realize all Fields with transfer action "accept"
+ private AdvertiseFields ! advertise fields
+ private RealizeFieldsWithTransferProvided ! realize connected Fields with transfer action "provide"
+ private ModifyDecompofMesh ! optionally modify the decomp/distr of transferred Grid/Mesh
+ private RealizeFieldsWithTransferAccept ! realize all Fields with transfer action "accept"
private DataInitialize ! finish initialization and resolve data dependencies
private SetRunClock
private med_meshinfo_create
@@ -129,7 +129,7 @@ subroutine SetServices(gcomp, rc)
integer, intent(out) :: rc
! local variables
- character(len=*),parameter :: subname=' (SetServices) '
+ character(len=*), parameter :: subname = '('//__FILE__//':SetServices)'
!-----------------------------------------------------------
rc = ESMF_SUCCESS
@@ -161,7 +161,7 @@ subroutine SetServices(gcomp, rc)
! The valid values are: [will provide, can provide, cannot provide]
call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
- phaseLabelList=(/"IPDv03p1"/), userRoutine=InitializeIPDv03p1, rc=rc)
+ phaseLabelList=(/"IPDv03p1"/), userRoutine=AdvertiseFields, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
!------------------
@@ -169,7 +169,7 @@ subroutine SetServices(gcomp, rc)
!------------------
call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
- phaseLabelList=(/"IPDv03p3"/), userRoutine=InitializeIPDv03p3, rc=rc)
+ phaseLabelList=(/"IPDv03p3"/), userRoutine=RealizeFieldsWithTransferProvided, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
!------------------
@@ -177,7 +177,7 @@ subroutine SetServices(gcomp, rc)
!------------------
call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
- phaseLabelList=(/"IPDv03p4"/), userRoutine=InitializeIPDv03p4, rc=rc)
+ phaseLabelList=(/"IPDv03p4"/), userRoutine=ModifyDecompofMesh, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
!------------------
@@ -185,7 +185,7 @@ subroutine SetServices(gcomp, rc)
!------------------
call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
- phaseLabelList=(/"IPDv03p5"/), userRoutine=InitializeIPDv03p5, rc=rc)
+ phaseLabelList=(/"IPDv03p5"/), userRoutine=RealizeFieldsWithTransferAccept, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
!------------------
@@ -567,10 +567,12 @@ subroutine InitializeP0(gcomp, importState, exportState, clock, rc)
character(len=CX) :: diro
character(len=CX) :: logfile
character(len=CX) :: diagfile
- character(len=*),parameter :: subname=' (InitializeP0) '
+ character(len=*), parameter :: subname = '('//__FILE__//':InitializeP0)'
!-----------------------------------------------------------
rc = ESMF_SUCCESS
+ call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
+
if (profile_memory) call ESMF_VMLogMemInfo("Entering "//trim(subname))
call ESMF_GridCompGet(gcomp, vm=vm, rc=rc)
if (ChkErr(rc,__LINE__,u_FILE_u)) return
@@ -646,7 +648,7 @@ end subroutine InitializeP0
!-----------------------------------------------------------------------
- subroutine InitializeIPDv03p1(gcomp, importState, exportState, clock, rc)
+ subroutine AdvertiseFields(gcomp, importState, exportState, clock, rc)
! Mediator advertises its import and export Fields and sets the
! TransferOfferGeomObject Attribute.
@@ -677,7 +679,7 @@ subroutine InitializeIPDv03p1(gcomp, importState, exportState, clock, rc)
type(med_fldlist_type), pointer :: fldListFr, fldListTo
type(med_fldList_entry_type), pointer :: fld
integer :: stat
- character(len=*),parameter :: subname=' (Advertise Fields) '
+ character(len=*), parameter :: subname = '('//__FILE__//':AdvertiseFields)'
!-----------------------------------------------------------
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
@@ -917,11 +919,11 @@ subroutine InitializeIPDv03p1(gcomp, importState, exportState, clock, rc)
if (profile_memory) call ESMF_VMLogMemInfo("Leaving "//trim(subname))
call ESMF_LogWrite(trim(subname)//": done", ESMF_LOGMSG_INFO)
- end subroutine InitializeIPDv03p1
+ end subroutine AdvertiseFields
!-----------------------------------------------------------------------------
- subroutine InitializeIPDv03p3(gcomp, importState, exportState, clock, rc)
+ subroutine RealizeFieldsWithTransferProvided(gcomp, importState, exportState, clock, rc)
! Realize connected Fields with transfer action "provide"
@@ -941,7 +943,7 @@ subroutine InitializeIPDv03p3(gcomp, importState, exportState, clock, rc)
type(InternalState) :: is_local
type(ESMF_VM) :: vm
integer :: n
- character(len=*),parameter :: subname=' (Realize Fields with Transfer Provide) '
+ character(len=*), parameter :: subname = '('//__FILE__//':RealizeFieldsWithTransferProvided)'
!-----------------------------------------------------------
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
@@ -981,11 +983,11 @@ subroutine InitializeIPDv03p3(gcomp, importState, exportState, clock, rc)
if (profile_memory) call ESMF_VMLogMemInfo("Leaving "//trim(subname))
call ESMF_LogWrite(trim(subname)//": done", ESMF_LOGMSG_INFO)
- end subroutine InitializeIPDv03p3
+ end subroutine RealizeFieldsWithTransferProvided
!-----------------------------------------------------------------------------
- subroutine InitializeIPDv03p4(gcomp, importState, exportState, clock, rc)
+ subroutine ModifyDecompofMesh(gcomp, importState, exportState, clock, rc)
! Optionally modify the decomp/distr of transferred Grid/Mesh
@@ -1002,7 +1004,8 @@ subroutine InitializeIPDv03p4(gcomp, importState, exportState, clock, rc)
! local variables
type(InternalState) :: is_local
integer :: n1
- character(len=*),parameter :: subname=' (Modify Decomp of Mesh/Grid) '
+ character(len=*), parameter :: subname = '('//__FILE__//':ModifyDecompofMesh)'
+
!-----------------------------------------------------------
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
@@ -1301,11 +1304,11 @@ subroutine realizeConnectedGrid(State,string,rc)
end subroutine realizeConnectedGrid
- end subroutine InitializeIPDv03p4
+ end subroutine ModifyDecompofMesh
!-----------------------------------------------------------------------------
- subroutine InitializeIPDv03p5(gcomp, importState, exportState, clock, rc)
+ subroutine RealizeFieldsWithTransferAccept(gcomp, importState, exportState, clock, rc)
use ESMF , only : ESMF_GridComp, ESMF_State, ESMF_Clock, ESMF_LogWrite
use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO, ESMF_StateIsCreated
@@ -1330,7 +1333,8 @@ subroutine InitializeIPDv03p5(gcomp, importState, exportState, clock, rc)
! local variables
type(InternalState) :: is_local
integer :: n1
- character(len=*),parameter :: subname=' (Realize Fields with Transfer Accept) '
+ character(len=*), parameter :: subname = '('//__FILE__//':RealizeFieldsWithTransferAccept)'
+
!-----------------------------------------------------------
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
@@ -1402,7 +1406,7 @@ subroutine completeFieldInitialization(State,rc)
integer, allocatable :: ungriddedLBound(:), ungriddedUBound(:)
logical :: isPresent
logical :: meshcreated
- character(len=*),parameter :: subname=' (Complete Field Initialization) '
+ character(len=*), parameter :: subname = '('//__FILE__//':completeFieldInitialization)'
!-----------------------------------------------------------
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
@@ -1512,7 +1516,7 @@ subroutine completeFieldInitialization(State,rc)
end subroutine completeFieldInitialization
- end subroutine InitializeIPDv03p5
+ end subroutine RealizeFieldsWithTransferAccept
!-----------------------------------------------------------------------------
@@ -1594,7 +1598,7 @@ subroutine DataInitialize(gcomp, rc)
logical,save :: first_call = .true.
real(r8) :: real_nx, real_ny
character(len=CX) :: msgString
- character(len=*), parameter :: subname=' (Data Initialization) '
+ character(len=*), parameter :: subname = '('//__FILE__//':DataInitialize)'
!-----------------------------------------------------------
call ESMF_LogWrite(trim(subname)//": called", ESMF_LOGMSG_INFO)
@@ -2200,8 +2204,8 @@ subroutine SetRunClock(gcomp, rc)
character(len=CL) :: stop_option
integer :: stop_n, stop_ymd
logical, save :: stopalarmcreated=.false.
+ character(len=*), parameter :: subname = '('//__FILE__//':SetRunClock)'
- character(len=*),parameter :: subname=' (Set Run Clock) '
!-----------------------------------------------------------
rc = ESMF_SUCCESS
@@ -2286,7 +2290,7 @@ subroutine med_meshinfo_create(FB, mesh_info, FBArea, rc)
real(r8), allocatable :: ownedElemCoords(:)
real(r8), pointer :: dataptr(:)
integer :: n, dimcount, fieldcount
- character(len=*),parameter :: subname=' (module_MED:med_meshinfo_create) '
+ character(len=*), parameter :: subname = '('//__FILE__//':med_meshinfo_create)'
!-------------------------------------------------------------------------------
rc= ESMF_SUCCESS
@@ -2359,7 +2363,7 @@ subroutine med_grid_write(grid, fileName, rc)
type(ESMF_ArrayBundle) :: arrayBundle
integer :: tileCount
logical :: isPresent
- character(len=*), parameter :: subname=' (Grid Write) '
+ character(len=*), parameter :: subname = '('//__FILE__//':med_grid_write)'
!-------------------------------------------------------------------------------
rc = ESMF_SUCCESS