! $Id$ ! ! Earth System Modeling Framework ! Copyright (c) 2002-2023, University Corporation for Atmospheric Research, ! Massachusetts Institute of Technology, Geophysical Fluid Dynamics ! Laboratory, University of Michigan, National Centers for Environmental ! Prediction, Los Alamos National Laboratory, Argonne National Laboratory, ! NASA Goddard Space Flight Center. ! Licensed under the University of Illinois-NCSA License. ! !============================================================================== !============================================================================== !ESMF_EXAMPLE String used by test script to count examples. !============================================================================== !----------------------------------------------------------------------------- !BOP !\subsubsection{Implement a user-code {\tt SetServices} routine} ! ! \label{sec:CplSetServ} ! ! Every {\tt ESMF\_CplComp} is required to provide and document ! a public set services routine. It can have any name, but must ! follow the declaration below: a subroutine which takes an ! {\tt ESMF\_CplComp} as the first argument, and ! an integer return code as the second. ! Both arguments are required and must {\em not} be declared as ! {\tt optional}. If an intent is specified in the interface it must be ! {\tt intent(inout)} for the first and {\tt intent(out)} for the ! second argument. ! ! The set services routine must call the ESMF method ! {\tt ESMF\_CplCompSetEntryPoint()} to ! register with the framework what user-code subroutines should be called ! to initialize, run, and finalize the component. There are ! additional routines which can be registered as well, for checkpoint ! and restart functions. ! ! Note that the actual subroutines being registered do not have to be ! public to this module; only the set services routine itself must ! be available to be used by other code. !EOP !BOC ! Example Coupler Component module ESMF_CouplerEx ! ESMF Framework module use ESMF implicit none public CPL_SetServices contains subroutine CPL_SetServices(comp, rc) type(ESMF_CplComp) :: comp ! must not be optional integer, intent(out) :: rc ! must not be optional ! Set the entry points for standard ESMF Component methods call ESMF_CplCompSetEntryPoint(comp, ESMF_METHOD_INITIALIZE, & userRoutine=CPL_Init, rc=rc) call ESMF_CplCompSetEntryPoint(comp, ESMF_METHOD_RUN, & userRoutine=CPL_Run, rc=rc) call ESMF_CplCompSetEntryPoint(comp, ESMF_METHOD_FINALIZE, & userRoutine=CPL_Final, rc=rc) rc = ESMF_SUCCESS end subroutine !EOC !BOP !\subsubsection{Implement a user-code {\tt Initialize} routine} ! ! \label{sec:CplInitialize} ! ! When a higher level component is ready to begin using an ! {\tt ESMF\_CplComp}, it will call its initialize routine. ! ! The component writer must supply a subroutine with the exact interface ! shown below. Arguments must not be declared as optional, and the types and ! order must match. ! ! At initialization time the component can allocate data space, open ! data files, set up initial conditions; anything it needs to do to ! prepare to run. ! ! The {\tt rc} return code should be set if an error occurs, otherwise ! the value {\tt ESMF\_SUCCESS} should be returned. !EOP !BOC subroutine CPL_Init(comp, importState, exportState, clock, rc) type(ESMF_CplComp) :: comp ! must not be optional type(ESMF_State) :: importState ! must not be optional type(ESMF_State) :: exportState ! must not be optional type(ESMF_Clock) :: clock ! must not be optional integer, intent(out) :: rc ! must not be optional print *, "Coupler Init starting" ! Add whatever code here needed ! Precompute any needed values, fill in any inital values ! needed in Import States rc = ESMF_SUCCESS print *, "Coupler Init returning" end subroutine CPL_Init !EOC !BOP !\subsubsection{Implement a user-code {\tt Run} routine} ! ! \label{sec:CplRun} ! ! During the execution loop, the run routine may be called many times. ! Each time it should read data from the {\tt importState}, use the ! {\tt clock} to determine what the current time is in the calling ! component, compute new values or process the data, ! and produce any output and place it in the {\tt exportState}. ! ! When a higher level component is ready to use the {\tt ESMF\_CplComp} ! it will call its run routine. ! ! The component writer must supply a subroutine with the exact interface ! shown below. Arguments must not be declared as optional, and the types and ! order must match. ! ! It is expected that this is where the bulk of the model computation ! or data analysis will occur. ! ! The {\tt rc} return code should be set if an error occurs, otherwise ! the value {\tt ESMF\_SUCCESS} should be returned. !EOP !BOC subroutine CPL_Run(comp, importState, exportState, clock, rc) type(ESMF_CplComp) :: comp ! must not be optional type(ESMF_State) :: importState ! must not be optional type(ESMF_State) :: exportState ! must not be optional type(ESMF_Clock) :: clock ! must not be optional integer, intent(out) :: rc ! must not be optional print *, "Coupler Run starting" ! Add whatever code needed here to transform Export state data ! into Import states for the next timestep. rc = ESMF_SUCCESS print *, "Coupler Run returning" end subroutine CPL_Run !EOC !BOP !\subsubsection{Implement a user-code {\tt Finalize} routine} ! ! \label{sec:CplFinalize} ! ! At the end of application execution, each {\tt ESMF\_CplComp} should ! deallocate data space, close open files, and flush final results. ! These functions should be placed in a finalize routine. ! ! The component writer must supply a subroutine with the exact interface ! shown below. Arguments must not be declared as optional, and the types and ! order must match. ! ! The {\tt rc} return code should be set if an error occurs, otherwise ! the value {\tt ESMF\_SUCCESS} should be returned. ! !EOP !BOC subroutine CPL_Final(comp, importState, exportState, clock, rc) type(ESMF_CplComp) :: comp ! must not be optional type(ESMF_State) :: importState ! must not be optional type(ESMF_State) :: exportState ! must not be optional type(ESMF_Clock) :: clock ! must not be optional integer, intent(out) :: rc ! must not be optional print *, "Coupler Final starting" ! Add whatever code needed here to compute final values and ! finish the computation. rc = ESMF_SUCCESS print *, "Coupler Final returning" end subroutine CPL_Final !EOC !------------------------------------------------------------------------- !BOP !\subsubsection{Implement a user-code {\tt SetVM} routine} ! ! \label{sec:CplSetVM} ! ! Every {\tt ESMF\_CplComp} can optionally provide and document ! a public set vm routine. It can have any name, but must ! follow the declaration below: a subroutine which takes an ! {\tt ESMF\_CplComp} as the first argument, and ! an integer return code as the second. ! Both arguments are required and must {\em not} be declared as ! {\tt optional}. If an intent is specified in the interface it must be ! {\tt intent(inout)} for the first and {\tt intent(out)} for the ! second argument. ! ! The set vm routine is the only place where the child component can ! use the {\tt ESMF\_CplCompSetVMMaxPEs()}, or ! {\tt ESMF\_CplCompSetVMMaxThreads()}, or ! {\tt ESMF\_CplCompSetVMMinThreads()} call to modify aspects of its own VM. ! ! A component's VM is started up right before its set services routine is ! entered. {\tt ESMF\_CplCompSetVM()} is executing in the parent VM, and must ! be called {\em before} {\tt ESMF\_CplCompSetServices()}. !EOP !BOC subroutine GComp_SetVM(comp, rc) type(ESMF_CplComp) :: comp ! must not be optional integer, intent(out) :: rc ! must not be optional type(ESMF_VM) :: vm logical :: pthreadsEnabled ! Test for Pthread support, all SetVM calls require it call ESMF_VMGetGlobal(vm, rc=rc) call ESMF_VMGet(vm, pthreadsEnabledFlag=pthreadsEnabled, rc=rc) if (pthreadsEnabled) then ! run PETs single-threaded call ESMF_CplCompSetVMMinThreads(comp, rc=rc) endif rc = ESMF_SUCCESS end subroutine end module ESMF_CouplerEx !EOC !------------------------------------------------------------------------- ! Note - the program below is here only to make this an executable ! program. It should not appear in the documentation for a Coupler Component. !------------------------------------------------------------------------- program ESMF_AppMainEx #include "ESMF.h" ! ! The ESMF Framework module use ESMF use ESMF_TestMod ! User supplied modules use ESMF_CouplerEx, only: CPL_SetServices implicit none ! ! Local variables integer :: rc logical :: finished type(ESMF_Clock) :: tclock type(ESMF_Calendar) :: gregorianCalendar type(ESMF_TimeInterval) :: timeStep type(ESMF_Time) :: startTime, stopTime character(ESMF_MAXSTR) :: cname type(ESMF_VM) :: vm type(ESMF_State) :: importState, exportState type(ESMF_CplComp) :: cpl integer :: finalrc, result character(ESMF_MAXSTR) :: testname character(ESMF_MAXSTR) :: failMsg !------------------------------------------------------------------------- !------------------------------------------------------------------------- write(failMsg, *) "Example failure" write(testname, *) "Example ESMF_CplEx" ! ------------------------------------------------------------------------------ ! ------------------------------------------------------------------------------ finalrc = ESMF_SUCCESS !------------------------------------------------------------------------- ! ! Initialize the Framework and get the default VM call ESMF_Initialize(vm=vm, defaultlogfilename="CplEx.Log", & logkindflag=ESMF_LOGKIND_MULTI, rc=rc) if (rc .ne. ESMF_SUCCESS) then print *, "Unable to initialize ESMF Framework" print *, "FAIL: ESMF_CplEx.F90" call ESMF_Finalize(endflag=ESMF_END_ABORT) endif !------------------------------------------------------------------------- ! ! ! ! Create, Init, Run, Finalize, Destroy Components. print *, "Application Example 1:" ! Create the top level application component cname = "Atmosphere Model Coupler" cpl = ESMF_CplCompCreate(name=cname, configFile="setup.rc", rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if ! This single user-supplied subroutine must be a public entry point. call ESMF_CplCompSetServices(cpl, userRoutine=CPL_SetServices, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if print *, "Comp Create returned, name = ", trim(cname) ! Create the necessary import and export states used to pass data ! between components. exportState = ESMF_StateCreate(name=cname, & stateintent=ESMF_STATEINTENT_EXPORT, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if importState = ESMF_StateCreate(name=cname, & stateintent=ESMF_STATEINTENT_IMPORT, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if ! See the TimeMgr document for the details on the actual code needed ! to set up a clock. ! initialize calendar to be Gregorian type gregorianCalendar = ESMF_CalendarCreate(ESMF_CALKIND_GREGORIAN, name="Gregorian", rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if ! initialize time interval to 6 hours call ESMF_TimeIntervalSet(timeStep, h=6, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if ! initialize start time to 5/1/2004 call ESMF_TimeSet(startTime, yy=2004, mm=5, dd=1, & calendar=gregorianCalendar, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if ! initialize stop time to 5/2/2004 call ESMF_TimeSet(stopTime, yy=2004, mm=5, dd=2, & calendar=gregorianCalendar, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if ! initialize the clock with the above values tclock = ESMF_ClockCreate(timeStep, startTime, stopTime=stopTime, & name="top clock", rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if ! Call the Init routine. There is an optional index number ! for those components which have multiple entry points. call ESMF_CplCompInitialize(cpl, importState=exportState, exportState=importState, clock=tclock, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if print *, "Comp Initialize complete" ! Main run loop. finished = .false. do while (.not. finished) call ESMF_CplCompRun(cpl, importState=exportState, exportState=importState, clock=tclock, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if call ESMF_ClockAdvance(tclock, timeStep=timestep) ! query clock for current time if (ESMF_ClockIsStopTime(tclock)) finished = .true. enddo print *, "Comp Run complete" ! Give the component a chance to write out final results, clean up. call ESMF_CplCompFinalize(cpl, importState=exportState, exportState=importState, clock=tclock, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if print *, "Comp Finalize complete" ! Destroy objects. call ESMF_ClockDestroy(tclock, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if call ESMF_CalendarDestroy(gregorianCalendar, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if call ESMF_CplCompDestroy(cpl, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if call ESMF_StateDestroy(importState, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if call ESMF_StateDestroy(exportState, rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if print *, "Destroy calls returned" print *, "Application Example 1 finished" ! IMPORTANT: ESMF_STest() prints the PASS string and the # of processors in the log ! file that the scripts grep for. call ESMF_STest((finalrc.eq.ESMF_SUCCESS), testname, failMsg, result, ESMF_SRCLINE) call ESMF_Finalize(rc=rc) if (rc.NE.ESMF_SUCCESS) then finalrc = ESMF_FAILURE end if if (finalrc.EQ.ESMF_SUCCESS) then print *, "PASS: ESMF_CplEx.F90" else print *, "FAIL: ESMF_CplEx.F90" end if end program ESMF_AppMainEx