ESMF_MapperSimpleTwoConcurrentCompsSTest.F90 Source File


Source Code

! $Id$
!
! System test code MapperSimpleTwoConcurrentComps

!-------------------------------------------------------------------------
!ESMF_disabled_MULTI_PROC_SYSTEM_TEST        String used by test script to count system tests.
!=========================================================================


!BOP
!
! !DESCRIPTION:
! System test MapperSimpleTwoConcurrentComps.
!   Concurrent, Concurrent Component test.
!   This system test demonstrates the use of ESMF coupling framework
! to couple 2 gridded components with 1 coupler component. The coupler
! component runs on the union of the PETs that are exclusively allocated
! to each individual gridded component.
!
! Component 1 exports data to the coupler which then redistributes the
! data to component 2. Component 1 and 2 runs concurrently because they
! reside on different PETs. The coupler also runs concurrently across PETs, however
! on each individual PET, it runs sequentially. In other words, each PET
! has a copy of the coupler that executes different code simultaneously.
! So this pattern constitutes a SPMD concurrency model.
!
! It's possible to reschedule the component execution by introducing wait
! and block semantic. Components on exclusive sets
! of PETs can be rescheduled to execute sequentially.
!
! This system test exercises the ESMF coupling framework to perform
! quick sort that can be useful in search engine, gnome sequencing, etc.
! The sorting result of component 1 is redistributed to component 2. Component
! 2 verifies the sorting result.
!
! This system test also captures the design of a typical hierarchical
! climate model with a coupler component that couples individual gridded components
! (e.g. atmosphere, land, and ocean).
!
!\begin{verbatim}

    program MapperSimpleTwoConcurrentComps

#include "ESMF_Conf.inc"
#include "ESMF.h"
#define ESMF_METHOD "MapperSimpleTwoConcurrentComps"

    ! ESMF Framework module
    use ESMF
    use ESMF_TestMod

    use user_model1, only : userm1_setvm, userm1_register
    use user_model2, only : userm2_setvm, userm2_register
    use user_coupler, only : usercpl_setvm, usercpl_register

    use comp_utils
    use mpi

    implicit none

    ! Dynamic Integer array type
    type DIArray
      integer, dimension(:), allocatable :: arr
    end type

    abstract interface
      subroutine iuser_setvm(comp, rc)
        use ESMF
        type(ESMF_GridComp) :: comp
        integer, intent(out) :: rc
      end subroutine iuser_setvm
      subroutine iuser_register(comp, rc)
          use ESMF
          type(ESMF_GridComp)  :: comp
          integer, intent(out) :: rc
      end subroutine iuser_register
    end interface

    type UModelFP
      procedure(iuser_setvm), pointer, nopass :: puser_setvm
      procedure(iuser_register), pointer, nopass :: puser_register
    end type

    integer, parameter :: NUM_UMODELS = 2
    type(UModelFP) :: umodel_func_ptrs(NUM_UMODELS)

    ! Local variables
    ! assert(NUM_COMPS > 0)
    integer, parameter :: NUM_COMPS = 8
    integer, parameter :: NUM_COMPS_PLUS_CPL = NUM_COMPS+1
    integer :: pet_id, npets, rc, localrc, userrc
    integer :: npets_comps(NUM_COMPS)
    integer :: npets_cpl
    integer :: petlist_start_comps(NUM_COMPS)
    integer :: petlist_start_cpl
    integer :: petlist_end_comps(NUM_COMPS)
    integer :: petlist_end_cpl
    integer :: i, j, k
    type(DIArray) :: petlist_comps(NUM_COMPS)
    integer, dimension(:), allocatable :: petlist_cpl
    character(len=ESMF_MAXSTR) :: comp_names(NUM_COMPS)
    character(len=ESMF_MAXSTR) :: cplname
    character(len=ESMF_MAXSTR) :: comp_phase_names(NUM_COMPS)
    type(ESMF_VM):: vm
    type(ESMF_State) :: cexps(NUM_COMPS), cimps(NUM_COMPS)
    type(ESMF_GridComp) :: comps(NUM_COMPS)
    real(ESMF_KIND_R8) :: comp_starts(NUM_COMPS), comp_ends(NUM_COMPS)
    double precision :: run_loop_start, run_loop_end
    double precision :: run_loop_wtime
    double precision :: comp_wtimes(NUM_COMPS)
    type(ESMF_CplComp) :: cpl

    ! instantiate a clock, a calendar, and timesteps
    !type(ESMF_Clock) :: clock_comps(1), clock_comps(2), clock_cpl
    integer, parameter :: CPL_IDX = 1
    integer, parameter :: GCOMP_SIDX = 2
    type(ESMF_Clock) :: clocks(NUM_COMPS_PLUS_CPL)
    type(ESMF_Calendar) :: gregorianCalendar
    type(ESMF_TimeInterval) :: timeSteps(NUM_COMPS_PLUS_CPL)
    type(ESMF_Time) :: startTime
    type(ESMF_Time) :: stopTime

    type(ESMF_Mapper) :: mapper

    type(ESMF_Time) :: dbg_time
    integer(ESMF_KIND_I8) :: dbg_stime

    ! cumulative result: count failures; no failures equals "all pass"
    integer :: testresult = 0
    integer :: result = 0

    character(ESMF_MAXSTR) :: tmpstr
    ! individual test name
    character(ESMF_MAXSTR) :: testname

    ! individual test failure message, and final status msg
    character(ESMF_MAXSTR) :: failMsg, finalMsg


!-------------------------------------------------------------------------
!-------------------------------------------------------------------------

    print *, "Start of System Test MapperSimpleTwoConcurrentComps."
    localrc = ESMF_SUCCESS
    rc = ESMF_SUCCESS

! Set the model function ptrs
    umodel_func_ptrs(1)%puser_setvm => userm1_setvm
    umodel_func_ptrs(1)%puser_register => userm1_register
    umodel_func_ptrs(2)%puser_setvm => userm2_setvm
    umodel_func_ptrs(2)%puser_register => userm2_register
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!    Create section
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!
    print *, "ESMF_Initialize ..."
    ! Initialize framework and get back default global VM
    call ESMF_Initialize(vm=vm, defaultlogfilename="ConcurrentCompSTest.Log", &
                        logkindflag=ESMF_LOGKIND_MULTI, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    print *, "ESMF_VMGet ..."
    ! Get number of PETs we are running with
    call ESMF_VMGet(vm, petCount=npets, localPET=pet_id, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

      ! Check for correct number of PETs
     if ( npets < NUM_COMPS ) then
        write(failMsg,'(A50,I6,A10)') "This system test does not run on fewer than ", NUM_COMPS, " PETs"
        call ESMF_LogSetError(ESMF_RC_ARG_BAD,&
            msg=failMsg,&
            ESMF_CONTEXT, rcToReturn=rc)
        call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      endif
      print *, "Allocating PETs among components ..."
      j = 0
      do i=1,NUM_COMPS-1
        npets_comps(i) = npets/NUM_COMPS
        petlist_start_comps(i) = j
        petlist_end_comps(i) = petlist_start_comps(i) + npets_comps(i) - 1
        j = j + npets_comps(i)
      end do
      npets_comps(NUM_COMPS) = npets - (NUM_COMPS - 1) * (npets/NUM_COMPS)
      petlist_start_comps(NUM_COMPS) = j
      petlist_end_comps(NUM_COMPS) = petlist_start_comps(NUM_COMPS) +&
                                      npets_comps(NUM_COMPS) - 1
      npets_cpl = npets
      petlist_start_cpl = 0
      petlist_end_cpl = petlist_start_cpl + npets_cpl - 1;

      do i=1,NUM_COMPS
        allocate(petlist_comps(i)%arr(npets_comps(i)))
      end do
      allocate(petlist_cpl(npets_cpl))
      do k=1,NUM_COMPS
        j = petlist_start_comps(k)
        do i=1,npets_comps(k)
          petlist_comps(k)%arr(i) = j
          j = j + 1
        end do
      end do
      j = petlist_start_cpl
      do i=1,npets_cpl
        petlist_cpl(i) = j
        j = j + 1
      end do
      
    print *, "Creating N model components..."
    ! Create the N model components and coupler
    do i=1,NUM_COMPS
      write(tmpstr, '(A12,I6)') "user model ", i
      comp_names(i) = trim(tmpstr)
      comps(i) = ESMF_GridCompCreate(name=comp_names(i), petList=petlist_comps(i)%arr, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
      print *, "Created component ", trim(comp_names(i)), "rc =", rc
    end do

    cplname = "user one-way coupler"
    cpl = ESMF_CplCompCreate(name=cplname, petList=petlist_cpl, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    print *, "Created component ", trim(cplname), ", rc =", rc

    do i=1,NUM_COMPS
      deallocate(petlist_comps(i)%arr)
    end do
    deallocate(petlist_cpl)
    !print *, "Comp Creates finished"

  print *, "Creating mapper...."
  !mapper = ESMF_MapperCreate(vm, configFile="./runseq.txt", rc=localrc)
  mapper = ESMF_MapperCreate(vm, rc=localrc)
  if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
    ESMF_CONTEXT, rcToReturn=rc)) &
    call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!  Register section
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------

  print *, "Registering components ..."
  do i=1,NUM_COMPS
    call ESMF_GridCompSetVM(comps(i),&
      userRoutine=umodel_func_ptrs(mod(i-1,NUM_UMODELS)+1)%puser_setvm,&
      userRc=userrc, rc=localrc)
    print *, "Comp1 SetVM finished, rc= ", localrc, userrc
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, rcToReturn=rc)) &
      call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
    if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, rcToReturn=rc)) &
      call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)

    call ESMF_GridCompSetServices(comps(i),&
      userRoutine=umodel_func_ptrs(mod(i-1,NUM_UMODELS)+1)%puser_register,&
      userRc=userrc, rc=localrc)
    print *, "Comp1 SetServices finished, rc= ", localrc, userrc
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, rcToReturn=rc)) &
      call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
    if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
      ESMF_CONTEXT, rcToReturn=rc)) &
      call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)

  end do

  call ESMF_CplCompSetVM(cpl, userRoutine=usercpl_setvm, &
    userRc=userrc, rc=localrc)
  print *, "Cpl SetVM finished, rc= ", localrc, userrc
  if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
    ESMF_CONTEXT, rcToReturn=rc)) &
    call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
  if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
    ESMF_CONTEXT, rcToReturn=rc)) &
    call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)

  call ESMF_CplCompSetServices(cpl, userRoutine=usercpl_register, &
    userRc=userrc, rc=localrc)
  print *, "Cpl SetServices finished, rc= ", localrc, userrc
  if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
    ESMF_CONTEXT, rcToReturn=rc)) &
    call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
  if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
    ESMF_CONTEXT, rcToReturn=rc)) &
    call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)

  ! Set mapper constraints
  !call ESMF_MapperSetConstraints(mapper, rc=localrc)
  !if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
  !  ESMF_CONTEXT, rcToReturn=rc)) &
  !  call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)


!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!  Create and initialize clocks for comps(1) and comps(2).
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
    ! initialize calendar to be Gregorian type
    gregorianCalendar = ESMF_CalendarCreate(ESMF_CALKIND_GREGORIAN, &
                                            name="Gregorian", rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    ! initialize time interval to 4 hours
    call ESMF_TimeIntervalSet(timeSteps(CPL_IDX), h=4, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    do i=1,NUM_COMPS
      call ESMF_TimeIntervalSet(timeSteps(GCOMP_SIDX+i-1), h=4, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    end do

    ! initialize start time to 5/01/2003
    call ESMF_TimeSet(startTime, yy=2003, mm=5, dd=1, &
                      calendar=gregorianCalendar, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    ! initialize stop time to 5/06/2003
    call ESMF_TimeSet(stopTime, yy=2003, mm=5, dd=6, &
                      calendar=gregorianCalendar, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    ! initialize the clock for comps(1) with the above values
    clocks(CPL_IDX) = ESMF_ClockCreate(timeSteps(CPL_IDX), startTime, stopTime=stopTime, &
                             name="Cpl Clock 1", rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    do i=1,NUM_COMPS
      write(tmpstr,"(A15,I6)") "Gcomp Clock", i
      clocks(GCOMP_SIDX+i-1) = ESMF_ClockCreate(timeSteps(GCOMP_SIDX+i-1), startTime, stopTime=stopTime, &
                               name=tmpstr, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    end do

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!  Init section
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------

  do i=1,NUM_COMPS,2
    write(tmpstr,"(A20,I6)") "export comps", i
    cexps(i) = ESMF_StateCreate(name=tmpstr,  &
                             stateintent=ESMF_STATEINTENT_EXPORT, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    call ESMF_GridCompInitialize(comps(i), exportState=cexps(i),&
       clock=clocks(GCOMP_SIDX+i-1), &
       userRC=userrc, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
    !print *, "Comp 1 Initialize finished, rc =", rc

    if((i+1) <= NUM_COMPS) then
      write(tmpstr,"(A20,I6)") "import comps", i+1
      cimps(i+1) = ESMF_StateCreate(name=tmpstr,  &
                               stateintent=ESMF_STATEINTENT_IMPORT, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
      call ESMF_GridCompInitialize(comps(i+1), importState=cimps(i+1),&
         clock=clocks(GCOMP_SIDX+i), &
         userRC=userrc, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
      if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      !print *, "Comp 2 Initialize finished, rc =", rc
    end if
  end do

    ! note that the coupler's import is comps(1)'s export
    do i=1,NUM_COMPS,2
      if((i+1) <= NUM_COMPS) then
        call ESMF_CplCompInitialize(cpl, importState=cexps(i), &
          exportState=cimps(i+1), clock=clocks(CPL_IDX), userRC=userrc, rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
            ESMF_CONTEXT, rcToReturn=rc)) &
            call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
        if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
            ESMF_CONTEXT, rcToReturn=rc)) &
            call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      end if
    end do
    !print *, "Coupler Initialize finished, rc =", rc

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!     Run section
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------

    do i=1,NUM_COMPS
      write(comp_phase_names(i),"(A15,I6)") "comp phase run", i
    end do
    do while (.not. ESMF_ClockIsStopTime(clocks(CPL_IDX), rc=localrc))

      print *, "PET ", pet_id, " starting time step..."

      run_loop_start = MPI_Wtime()
      ! Uncomment the following call to ESMF_GridCompWait() to sequentialize
      ! comps(1) and comps(2). The following ESMF_GridCompWait() call will block
      ! all PETs until comps(2) has returned. Consequently comps(1) will not be
      ! run until comps(2) has returned.
      !call ESMF_GridCompWait(comps(2), syncflag=ESMF_SYNC_BLOCKING, rc=localrc)
      !print *, "Comp 2 Wait returned, rc =", localrc
      !if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      !  ESMF_CONTEXT, rcToReturn=rc)) &
      !  call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

      ! Run the first component:
      ! After the first time thru the loop this will be running concurrently
      ! with the second component since comps(1) and comps(2) are defined on
      ! exclusive sets of PETs
      do i=1,NUM_COMPS,2
        !print *, "I am calling into GridCompRun(comps(1))"
        comp_starts(i) = MPI_Wtime()
        !call ESMF_GridCompRun(comps(1), exportState=cexps(1), clock=clocks(GCOMP_SIDX), &
        !  userRc=userrc, rc=localrc)
        call ESMF_GridCompRun(comps(i), clock=clocks(GCOMP_SIDX+i-1), &
          userRc=userrc, rc=localrc)
        print *, "Comp ", i, " Run returned, rc =", localrc
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
        if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
        comp_ends(i) = MPI_Wtime()
      end do

      ! Uncomment the following calls to ESMF_GridCompWait() to sequentialize
      ! comps(1), comps(2) and the coupler. The following ESMF_GridCompWait() calls
      ! will block all PETs until comps(1) and comps(2) have returned. Consequently
      ! the coupler component will not be run until comps(1) and comps(2) have
      ! returned.
      !call ESMF_GridCompWait(comps(1), syncflag=ESMF_SYNC_BLOCKING, rc=localrc)
      !print *, "Comp 1 Wait returned, rc =", localrc
      !if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      !  ESMF_CONTEXT, rcToReturn=rc)) &
      !  call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
      !call ESMF_GridCompWait(comps(2), syncflag=ESMF_SYNC_BLOCKING, rc=localrc)
      !print *, "Comp 2 Wait returned, rc =", localrc
      !if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      !  ESMF_CONTEXT, rcToReturn=rc)) &
      !  call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

      ! Run the coupler:
      ! The coupler will run in "per-PET sequential" mode because it runs on
      ! the union of all PETs. Depending on the per-PET runtime of comps(1) and
      ! comps(2) some PETs may start/finish executing the coupler at different
      ! times. There is no intrinsic inter PET synchronization in calling
      ! component methods via CompI/R/F(). However, collective communication
      ! calls contained in the user written coupler methods will indirectly
      ! lead to inter PET synchronization of the coupler component.
      !print *, "I am calling into CplCompRun(cpl)"
      !call ESMF_CplCompRun(cpl, importState=cexps(1), &
      !  exportState=cimps(2), clock=clocks(CPL_IDX), userRc=userrc, rc=localrc)
      call ESMF_CplCompRun(cpl,&
        clock=clocks(CPL_IDX), userRc=userrc, rc=localrc)
      !print *, "Coupler Run returned, rc =", localrc
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)

      ! Uncomment the following call to ESMF_GridCompWait() to sequentialize
      ! comps(1) and comps(2). The following ESMF_GridCompWait() call will block
      ! all PETs until comps(1) has returned. Consequently comps(2) will not be
      ! run until comps(2) has returned.
      !call ESMF_GridCompWait(comps(1), syncflag=ESMF_SYNC_BLOCKING, rc=localrc)
      !print *, "Comp 1 Wait returned, rc =", localrc
      !if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
      !  ESMF_CONTEXT, rcToReturn=rc)) &
      !  call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

      ! Run the second component:
      ! Since comps(1) and comps(2) are defined on exclusive sets of PETs those PET
      ! that are part of comps(1) will not block in the following call but proceed
      ! to the next loop increment, executing comps(1) concurrently with comps(2).
      do i=2,NUM_COMPS,2
        !print *, "I am calling into GridCompRun(comps(2))"
        comp_starts(i) = MPI_Wtime()
        !call ESMF_GridCompRun(comps(2), importState=cimps(2), clock=clocks(GCOMP_SIDX+1), &
        !  userRc=userrc, rc=localrc)
        call ESMF_GridCompRun(comps(i), clock=clocks(GCOMP_SIDX+i-1), &
          userRc=userrc, rc=localrc)
        print *, "Comp ", i, " Run returned, rc =", localrc
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
        if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
        comp_ends(2) = MPI_Wtime()
      end do

      run_loop_end = MPI_Wtime() - run_loop_start
      do i=1,NUM_COMPS
        call MPI_Allreduce(comp_ends(i), comp_wtimes(i),&
              1, MPI_DOUBLE_PRECISION,&
              MPI_MAX, MPI_COMM_WORLD, rc)
      end do

      call MPI_Allreduce(run_loop_end, run_loop_wtime, 1, MPI_DOUBLE_PRECISION,&
            MPI_MAX, MPI_COMM_WORLD, rc)

      do i=1,NUM_COMPS
        print *, "comps(", i, ") = ", comp_wtimes(i), "s"
      end do
      print *, "run loop = ", run_loop_wtime, "s"

      print *, "Setting comp infos..."
      do i=1,NUM_COMPS
        ! Contact mapper
        call ESMF_MapperSetCompInfo(mapper,&
              len_trim(comp_names(i)), comp_names(i),&
              len_trim(comp_phase_names(i)), comp_phase_names(i),&
              petlist_start_comps(i), petlist_end_comps(i),&      
              comp_starts(i), comp_ends(i),&
              rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=localrc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      end do
      
      print *, "Optimizing PET layouts using mapper..."
      ! Optimize using the mapper
      call ESMF_MapperOptimize(mapper, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=localrc)) &
        call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)

      print *, "Retrieving optimized PET layouts from mapper..."
      do i=1,NUM_COMPS
        ! Contact mapper
        call ESMF_MapperGetCompInfo(mapper,&
              len_trim(comp_names(i)), comp_names(i),&
              len_trim(comp_phase_names(i)), comp_phase_names(i),&
              startPet=petlist_start_comps(i), endPet=petlist_end_comps(i),&      
              rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=localrc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      end do
      
      print *, "Recreating components..."
      do i=1,NUM_COMPS
        ! Recreate the components using info from mapper
        call user_comp_recreate(comps(i),&
          umodel_func_ptrs(mod(i-1,NUM_UMODELS) + 1)%puser_setvm,&
          umodel_func_ptrs(mod(i-1,NUM_UMODELS) + 1)%puser_register,&
          petlist_start_comps(i), petlist_end_comps(i), mapper, localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=localrc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      end do

      do i=1,NUM_COMPS
        call ESMF_ClockAdvance(clocks(GCOMP_SIDX+i-1), rc=localrc)
        if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
        !call ESMF_ClockPrint(clock_comps(1), rc=localrc)
      end do

      call ESMF_ClockAdvance(clocks(CPL_IDX), rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
      !call ESMF_ClockPrint(clock_cpl, rc=localrc)

      print *, "... time step finished on PET ", pet_id, "."

    enddo

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!     Finalize section
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!     Print result

    do i=1,NUM_COMPS,2
      call ESMF_GridCompFinalize(comps(i), exportState=cexps(i), clock=clocks(GCOMP_SIDX+i-1), &
         userRc=userrc, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
      if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      !print *, "Comp 1 Finalize finished, rc =", rc
    end do

    do i=2,NUM_COMPS,2
      call ESMF_GridCompFinalize(comps(i), importState=cimps(i), clock=clocks(GCOMP_SIDX+i-1), &
         userRc=userrc, rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
      if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
      !print *, "Comp 2 Finalize finished, rc =", rc
    end do

    call ESMF_CplCompFinalize(cpl, importState=cexps(1), &
      exportState=cimps(2), clock=clocks(CPL_IDX), userRc=userrc, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    if (ESMF_LogFoundError(userrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT)
    !print *, "Coupler Finalize finished, rc =", rc


    !print *, "Comp Finalize returned"

!
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!     Destroy section
!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
!     Clean up

    do i=1,NUM_COMPS,2
      call ESMF_StateDestroy(cexps(i), rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    end do
    do i=2,NUM_COMPS,2
      call ESMF_StateDestroy(cimps(i), rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    end do

    do i=1,NUM_COMPS
      call ESMF_ClockDestroy(clocks(GCOMP_SIDX+i-1), rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    end do
    call ESMF_ClockDestroy(clocks(CPL_IDX), rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    call ESMF_CalendarDestroy(gregorianCalendar, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    do i=1,NUM_COMPS
      call ESMF_GridCompDestroy(comps(i), rc=localrc)
      if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
          ESMF_CONTEXT, rcToReturn=rc)) &
          call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    end do
    call ESMF_CplCompDestroy(cpl, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)

    call ESMF_MapperDestroy(mapper, rc=localrc)
    if (ESMF_LogFoundError(localrc, ESMF_ERR_PASSTHRU, &
        ESMF_CONTEXT, rcToReturn=rc)) &
        call ESMF_Finalize(rc=localrc, endflag=ESMF_END_ABORT)
    !print *, "All Destroy routines done"

!-------------------------------------------------------------------------
!-------------------------------------------------------------------------
    print *, "System Test MapperSimpleTwoConcurrentComps complete."
    rc = localrc

    ! Normal ESMF Test output
    write(failMsg, *) "System Test failure"
    write(testname, *) "System Test MapperSimpleTwoConcurrentComps: Array Concurrent Components"

    if (rc .eq. ESMF_SUCCESS) then
      write(finalMsg, *) "SUCCESS: Concurrent Component test finished correctly."
    else
        write(finalMsg, *) "System Test did not succeed.  Error code ", rc
    endif
    write(0, *) ""
    write(0, *) trim(testname)
    write(0, *) trim(finalMsg)
    write(0, *) ""


    ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors
    ! into the Log file that the scripts grep for.
    call ESMF_STest((rc.eq.ESMF_SUCCESS), testname, failMsg, result, &
    __FILE__, &
    __LINE__)

    call ESMF_Finalize()

    end program MapperSimpleTwoConcurrentComps

!\end{verbatim}