! $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. ! !============================================================================== ! !BOE !\subsection{Example NUOPC Model cap} !\label{sec:basicexamplecap} ! ! The following code is a starting point for creating a basic NUOPC ! Model cap. ! !EOE !BOC module MYMODEL !----------------------------------------------------------------------------- ! Basic NUOPC Model cap !----------------------------------------------------------------------------- use ESMF use NUOPC use NUOPC_Model, & modelSS => SetServices ! add use statements for your model's initialization ! and run subroutines implicit none private public :: SetServices !----------------------------------------------------------------------------- contains !----------------------------------------------------------------------------- subroutine SetServices(model, rc) type(ESMF_GridComp) :: model integer, intent(out) :: rc rc = ESMF_SUCCESS ! derive from NUOPC_Model call NUOPC_CompDerive(model, modelSS, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out ! specialize model call NUOPC_CompSpecialize(model, specLabel=label_Advertise, & specRoutine=Advertise, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out call NUOPC_CompSpecialize(model, specLabel=label_RealizeProvided, & specRoutine=Realize, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out call NUOPC_CompSpecialize(model, specLabel=label_Advance, & specRoutine=Advance, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out end subroutine !----------------------------------------------------------------------------- subroutine Advertise(model, rc) type(ESMF_GridComp) :: model integer, intent(out) :: rc rc = ESMF_SUCCESS ! Eventually, you will advertise your model's import and ! export fields in this phase. For now, however, call ! your model's initialization routine(s). ! call my_model_init() end subroutine !----------------------------------------------------------------------------- subroutine Realize(model, rc) type(ESMF_GridComp) :: model integer, intent(out) :: rc rc = ESMF_SUCCESS ! Eventually, you will realize your model's fields here, ! but leave empty for now. end subroutine !----------------------------------------------------------------------------- subroutine Advance(model, rc) type(ESMF_GridComp) :: model integer, intent(out) :: rc ! local variables type(ESMF_Clock) :: clock type(ESMF_State) :: importState, exportState rc = ESMF_SUCCESS ! query the Component for its clock, importState and exportState call NUOPC_ModelGet(model, modelClock=clock, importState=importState, & exportState=exportState, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out ! HERE THE MODEL ADVANCES: currTime -> currTime + timeStep ! Because of the way that the internal Clock was set by default, ! its timeStep is equal to the parent timeStep. As a consequence the ! currTime + timeStep is equal to the stopTime of the internal Clock ! for this call of the Advance() routine. call ESMF_ClockPrint(clock, options="currTime", & preString="------>Advancing MODEL from: ", rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out call ESMF_ClockPrint(clock, options="stopTime", & preString="--------------------------------> to: ", rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out ! Call your model's timestep routine here ! call my_model_update() end subroutine end module !EOC ! A basic NUOPC Driver module DRIVER use ESMF use NUOPC use NUOPC_Driver, & driver_routine_SS => SetServices, & driver_label_SetModelServices => label_SetModelServices use MYMODEL, only: mymodelSS => SetServices implicit none private integer, parameter :: stepCount = 5 real(ESMF_KIND_R8), parameter :: stepTime = 30.D0 ! step time [s] public :: SetServices !----------------------------------------------------------------------------- contains !----------------------------------------------------------------------------- subroutine SetServices(drvr, rc) type(ESMF_GridComp) :: drvr integer, intent(out) :: rc rc = ESMF_SUCCESS ! NUOPC_Driver registers the generic methods call NUOPC_CompDerive(drvr, driver_routine_SS, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out ! attach specializing method(s) call NUOPC_CompSpecialize(drvr, specLabel=driver_label_SetModelServices, & specRoutine=SetModelServices, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out end subroutine SetServices !----------------------------------------------------------------------------- subroutine SetModelServices(drvr, rc) type(ESMF_GridComp) :: drvr integer, intent(out) :: rc ! local variables integer :: localrc type(ESMF_GridComp) :: child type(ESMF_CplComp) :: connector type(ESMF_Time) :: startTime type(ESMF_Time) :: stopTime type(ESMF_TimeInterval) :: timeStep type(ESMF_Clock) :: internalClock rc = ESMF_SUCCESS call NUOPC_DriverAddComp(drvr, "MYMODEL", mymodelSS, comp=child, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out ! set the driver clock call ESMF_TimeSet(startTime, s = 0, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & call ESMF_Finalize(endflag=ESMF_END_ABORT) call ESMF_TimeSet(stopTime, s_r8 = stepTime * stepCount, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & call ESMF_Finalize(endflag=ESMF_END_ABORT) call ESMF_TimeIntervalSet(timeStep, s_r8 = stepTime, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & call ESMF_Finalize(endflag=ESMF_END_ABORT) internalClock = ESMF_ClockCreate(name="Driver Clock", & timeStep=timeStep, startTime=startTime, stopTime=stopTime, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & call ESMF_Finalize(endflag=ESMF_END_ABORT) call ESMF_GridCompSet(drvr, clock=internalClock, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & line=__LINE__, & file=__FILE__)) & return ! bail out end subroutine SetModelServices end module program ESMF_NUOPCBasicModelEx !------------------------------------------------------------------------------ !ESMF_EXAMPLE String used by test script to count examples. !============================================================================== #include "ESMF.h" ! ESMF Framework module use ESMF use ESMF_TestMod use DRIVER, only: driverSS => SetServices implicit none ! Local variables type(ESMF_GridComp) :: drvr integer :: rc integer :: finalrc integer :: result = 0 ! all pass character(ESMF_MAXSTR) :: testname character(ESMF_MAXSTR) :: failMsg finalrc = ESMF_SUCCESS !------------------------------------------------------------------------- !------------------------------------------------------------------------- write(failMsg, *) "Example failure" write(testname, *) "Example ESMF_NUOPCBasicModelEx" !------------------------------------------------------------------------- !------------------------------------------------------------------------- call ESMF_Initialize(defaultlogfilename="NUOPCBasicModelEx.Log", & defaultCalKind=ESMF_CALKIND_GREGORIAN, & logkindflag=ESMF_LOGKIND_MULTI, rc=rc) !------------------------------------------------------------------------- print *, "NUOPC Basic Model template run" ! instantiate the cap and do a sanity check run drvr = ESMF_GridCompCreate(name="Driver", rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE call ESMF_GridCompSetServices(drvr, userRoutine=driverSS, rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE call ESMF_GridCompInitialize(drvr, phase=0, rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE call ESMF_GridCompInitialize(drvr, rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE call ESMF_GridCompRun(drvr, rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE call ESMF_GridCompFinalize(drvr, rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE call ESMF_GridCompDestroy(drvr, rc=rc) if (rc.NE.ESMF_SUCCESS) finalrc = ESMF_FAILURE !------------------------------------------------------------------------- ! 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) finalrc = ESMF_FAILURE if (finalrc.EQ.ESMF_SUCCESS) then print *, "PASS: ESMF_NUOPCBasicModelEx.F90" else print *, "FAIL: ESMF_NUOPCBasicModelEx.F90" end if end program ESMF_NUOPCBasicModelEx