5 ! ESMF-specific modules for building WRF as an ESMF component.
7 ! This source file is only built when ESMF coupling is used.
13 MODULE module_metadatautils
15 ! This module defines component-independent "model metadata" utilities
16 ! used for ESMF coupling.
18 !TODO: Upgrade this later to support multiple coupling intervals via Alarms
19 !TODO: associated with top-level clock. Do this by adding TimesAttachedToState()
20 !TODO: inquiry function that will test an ESMF_State to see if the times are
21 !TODO: present via names defined in this module. Then call it for every
22 !TODO: component and resolve conflicts (somehow) for cases where two components
23 !TODO: define conflicting clocks. Of course, a component is allowed to not attach
24 !TODO: times to a state at all, if it can handle any time step.
26 !TODO: Replace meta-data names with "model metadata" conventions such as CF
27 !TODO: (once they exist)
29 !TODO: Refactor to remove duplication of hard-coded names.
35 ! everything is private by default
39 PUBLIC AttachTimesToState
40 PUBLIC GetTimesFromStates
41 PUBLIC AttachDecompToState
42 PUBLIC GetDecompFromState
45 CHARACTER (ESMF_MAXSTR) :: str
51 ! Attach time information to state as meta-data.
52 ! Update later to use some form of meta-data standards/conventions for
53 ! model "time" meta-data.
54 SUBROUTINE AttachTimesToState( state, startTime, stopTime, couplingInterval )
55 TYPE(ESMF_State), INTENT(INOUT) :: state
56 TYPE(ESMF_Time), INTENT(INOUT) :: startTime
57 TYPE(ESMF_Time), INTENT(INOUT) :: stopTime
58 TYPE(ESMF_TimeInterval), INTENT(INOUT) :: couplingInterval
61 INTEGER :: year, month, day, hour, minute, second
62 INTEGER(ESMF_KIND_I4) :: timevals(6) ! big enough to hold the vars listed above
64 CALL ESMF_TimeGet(startTime, yy=year, mm=month, dd=day, &
65 h=hour, m=minute, s=second, rc=rc)
66 IF ( rc /= ESMF_SUCCESS ) THEN
67 CALL wrf_error_fatal ( 'ESMF_TimeGet(startTime) failed' )
75 CALL ESMF_AttributeSet(state, 'ComponentStartTime', timevals, itemCount=SIZE(timevals), rc=rc)
76 IF ( rc /= ESMF_SUCCESS ) THEN
77 CALL wrf_error_fatal ( 'ESMF_AttributeSet(ComponentStartTime) failed' )
80 CALL ESMF_TimeGet(stopTime, yy=year, mm=month, dd=day, &
81 h=hour, m=minute, s=second, rc=rc)
82 IF ( rc /= ESMF_SUCCESS ) THEN
83 CALL wrf_error_fatal ( 'ESMF_TimeGet(stopTime) failed' )
91 CALL ESMF_AttributeSet(state, 'ComponentStopTime', timevals, itemCount=SIZE(timevals), rc=rc)
92 IF ( rc /= ESMF_SUCCESS ) THEN
93 CALL wrf_error_fatal ( 'ESMF_AttributeSet(ComponentStopTime) failed' )
96 CALL ESMF_TimeIntervalGet(couplingInterval, yy=year, mm=month, d=day, &
97 h=hour, m=minute, s=second, rc=rc)
98 IF ( rc /= ESMF_SUCCESS ) THEN
99 CALL wrf_error_fatal ( 'ESMF_TimeIntervalGet(couplingInterval) failed' )
107 CALL ESMF_AttributeSet(state, 'ComponentCouplingInterval', timevals, itemCount=SIZE(timevals), rc=rc)
108 IF ( rc /= ESMF_SUCCESS ) THEN
109 CALL wrf_error_fatal ( 'ESMF_AttributeSet(ComponentCouplingInterval) failed' )
111 END SUBROUTINE AttachTimesToState
115 ! Extract time information attached as meta-data from a single
117 ! Update later to use some form of meta-data standards/conventions for
118 ! model "time" meta-data.
119 SUBROUTINE GetTimesFromState( state, startTime, stopTime, couplingInterval, rc )
120 TYPE(ESMF_State), INTENT(INOUT) :: state
121 TYPE(ESMF_Time), INTENT(INOUT) :: startTime
122 TYPE(ESMF_Time), INTENT(INOUT) :: stopTime
123 TYPE(ESMF_TimeInterval), INTENT(INOUT) :: couplingInterval
124 INTEGER, INTENT(INOUT) :: rc
126 INTEGER :: year, month, day, hour, minute, second
127 INTEGER(ESMF_KIND_I4) :: timevals(6) ! big enough to hold the vars listed above
128 INTEGER :: thecount ! 'one attribute ... ah ah ah. TWO attributes! ah ah ah!!
131 thecount = SIZE(timevals)
132 CALL ESMF_AttributeGet(state, 'ComponentStartTime', timevals, itemCount=thecount, rc=rc)
133 IF ( rc /= ESMF_SUCCESS ) THEN
134 !JM return but don't fail; let the caller figure out what to do
143 CALL ESMF_TimeSet(startTime, yy=year, mm=month, dd=day, &
144 h=hour, m=minute, s=second, rc=rc)
145 IF ( rc /= ESMF_SUCCESS ) THEN
146 CALL wrf_error_fatal ( 'ESMF_TimeSet(startTime) failed' )
149 thecount = SIZE(timevals)
150 CALL ESMF_AttributeGet(state, 'ComponentStopTime', timevals, itemCount=thecount, rc=rc)
151 IF ( rc /= ESMF_SUCCESS ) THEN
152 !JM return but don't fail; let the caller figure out what to do
153 !CALL wrf_error_fatal ( 'ESMF_AttributeGet(ComponentStopTime) failed' )
162 CALL ESMF_TimeSet(stopTime, yy=year, mm=month, dd=day, &
163 h=hour, m=minute, s=second, rc=rc)
164 IF ( rc /= ESMF_SUCCESS ) THEN
165 CALL wrf_error_fatal ( 'ESMF_TimeSet(stopTime) failed' )
168 thecount = SIZE(timevals)
169 CALL ESMF_AttributeGet(state, 'ComponentCouplingInterval', timevals, itemCount=thecount, rc=rc)
170 IF ( rc /= ESMF_SUCCESS ) THEN
171 !JM return but don't fail; let the caller figure out what to do
172 !CALL wrf_error_fatal ( 'ESMF_AttributeGet(ComponentCouplingInterval) failed' )
181 CALL ESMF_TimeIntervalSet(couplingInterval, yy=year, mm=month, d=day, &
182 h=hour, m=minute, s=second, rc=rc)
183 IF ( rc /= ESMF_SUCCESS ) THEN
184 CALL wrf_error_fatal ( 'ESMF_TimeIntervalSet(couplingInterval) failed' )
186 END SUBROUTINE GetTimesFromState
190 ! Extract time information attached as meta-data from one or more
191 ! ESMF_States. To use this with more than one ESMF_State, put the
192 ! ESMF_States into a single ESMF_State. If times differ, an attempt
193 ! is made to reconcile them.
194 SUBROUTINE GetTimesFromStates( state, startTime, stopTime, couplingInterval )
196 TYPE(ESMF_State), INTENT(INOUT) :: state
197 TYPE(ESMF_Time), INTENT(INOUT) :: startTime
198 TYPE(ESMF_Time), INTENT(INOUT) :: stopTime
199 TYPE(ESMF_TimeInterval), INTENT(INOUT) :: couplingInterval
202 INTEGER :: numItems, numStates, i, istate
203 TYPE(ESMF_StateItem_Flag), ALLOCATABLE :: itemTypes(:)
204 TYPE(ESMF_State) :: tmpState
205 CHARACTER (len=ESMF_MAXSTR), ALLOCATABLE :: itemNames(:)
206 TYPE(ESMF_Time), ALLOCATABLE :: startTimes(:)
207 TYPE(ESMF_Time), ALLOCATABLE :: stopTimes(:)
208 TYPE(ESMF_TimeInterval), ALLOCATABLE :: couplingIntervals(:)
209 CHARACTER (len=132) :: mess
211 ! Unfortunately, implementing this is unnecessarily difficult due
212 ! to lack of Iterators for ESMF_State.
214 ! Since there are no convenient iterators for ESMF_State,
215 ! write a lot of code...
216 ! Figure out how many items are in the ESMF_State
217 CALL ESMF_StateGet(state, itemCount=numItems, rc=rc)
218 IF ( rc /= ESMF_SUCCESS) THEN
219 CALL wrf_error_fatal ( 'ESMF_StateGet(numItems) failed' )
221 ! allocate an array to hold the types of all items
222 ALLOCATE( itemTypes(numItems) )
223 ! allocate an array to hold the names of all items
224 ALLOCATE( itemNames(numItems) )
225 ! get the item types and names
226 CALL ESMF_StateGet(state, itemtypeList=itemTypes, &
227 itemNameList=itemNames, rc=rc)
228 IF ( rc /= ESMF_SUCCESS) THEN
229 WRITE(str,*) 'ESMF_StateGet itemTypes failed with rc = ', rc
230 CALL wrf_error_fatal ( str )
232 ! count how many items are ESMF_States
235 IF ( itemTypes(i) == ESMF_STATEITEM_STATE ) THEN
236 numStates = numStates + 1
239 ALLOCATE( startTimes(numStates), stopTimes(numStates), &
240 couplingIntervals(numStates) )
241 IF ( numStates > 0) THEN
242 ! finally, extract nested ESMF_States by name, if there are any
243 ! (should be able to do this by index at least!)
246 IF ( itemTypes(i) == ESMF_STATEITEM_STATE ) THEN
247 CALL ESMF_StateGet( state, itemName=TRIM(itemNames(i)), &
248 nestedState=tmpState, rc=rc )
249 IF ( rc /= ESMF_SUCCESS) THEN
250 WRITE(str,*) 'ESMF_StateGet(',TRIM(itemNames(i)),') failed'
251 CALL wrf_error_fatal ( str )
254 CALL GetTimesFromState( tmpState, startTimes(istate), &
256 couplingIntervals(istate), rc )
257 IF ( rc /= ESMF_SUCCESS ) THEN
262 IF ( istate .EQ. 1 ) THEN
263 ! this presupposes that 1 of the child states exist and has
264 ! valid times in it. Use that one.
265 WRITE(mess,*)'WARNING: Only ',TRIM(itemNames(1)),&
266 ' is valid and has time info in it. Using that.'
267 CALL wrf_message(mess)
268 CALL ESMF_StateGet( state, itemName=TRIM(itemNames(1)), &
269 nestedState=tmpState, rc=rc )
270 CALL GetTimesFromState( tmpState, startTime, stopTime, &
271 couplingInterval , rc )
272 ELSE IF ( istate .GT. 1 ) THEN
273 CALL ReconcileTimes( startTimes, stopTimes, couplingIntervals, &
274 startTime, stopTime, couplingInterval )
276 CALL wrf_error_fatal('no valid states with times found. giving up.')
279 ! there are no nested ESMF_States so use parent state only
280 CALL GetTimesFromState( state, startTime, stopTime, &
281 couplingInterval , rc )
285 DEALLOCATE( itemTypes )
286 DEALLOCATE( itemNames )
287 DEALLOCATE( startTimes, stopTimes, couplingIntervals )
289 END SUBROUTINE GetTimesFromStates
292 ! Reconcile all times and intervals in startTimes, stopTimes, and
293 ! couplingIntervals and return the results in startTime, stopTime, and
294 ! couplingInterval. Abort if reconciliation is not possible.
295 SUBROUTINE ReconcileTimes( startTimes, stopTimes, couplingIntervals, &
296 startTime, stopTime, couplingInterval )
297 TYPE(ESMF_Time), INTENT(INOUT) :: startTimes(:)
298 TYPE(ESMF_Time), INTENT(INOUT) :: stopTimes(:)
299 TYPE(ESMF_TimeInterval), INTENT(INOUT) :: couplingIntervals(:)
300 TYPE(ESMF_Time), INTENT(INOUT) :: startTime
301 TYPE(ESMF_Time), INTENT(INOUT) :: stopTime
302 TYPE(ESMF_TimeInterval), INTENT(INOUT) :: couplingInterval
304 INTEGER :: numTimes, numTimesTmp, i
306 ! how many sets of time info?
307 numTimes = SIZE(startTimes)
308 IF ( numTimes < 2 ) THEN
309 CALL wrf_error_fatal ( 'SIZE(startTimes) too small' )
311 numTimesTmp = SIZE(stopTimes)
312 IF ( numTimes /= numTimesTmp ) THEN
313 CALL wrf_error_fatal ( 'incorrect SIZE(stopTimes)' )
315 numTimesTmp = SIZE(couplingIntervals)
316 IF ( numTimes /= numTimesTmp ) THEN
317 CALL wrf_error_fatal ( 'incorrect SIZE(couplingIntervals)' )
321 !TODO: For now this is very simple. Fancy it up later.
324 startTime = startTimes(i)
325 stopTime = stopTimes(i)
326 couplingInterval = couplingIntervals(i)
328 !jm IF ( startTimes(i) /= startTime ) THEN
329 !jm CALL wrf_message ( 'ReconcileTimes: inconsistent startTimes. Using first.' )
330 !jm startTimes(i) = startTime
332 !jm IF ( stopTimes(i) /= stopTime ) THEN
333 !jm CALL wrf_message ( 'ReconcileTimes: inconsistent stopTimes. Using first.' )
334 !jm stopTimes(i) = stopTime
336 IF ( startTimes(i) > startTime ) THEN
337 CALL wrf_message ( 'ReconcileTimes: inconsistent startTimes. Using later.' )
338 startTime = startTimes(i)
340 IF ( stopTimes(i) < stopTime ) THEN
341 CALL wrf_message ( 'ReconcileTimes: inconsistent stopTimes. Using earlier.' )
342 stopTime = stopTimes(i)
344 IF ( couplingIntervals(i) /= couplingInterval ) THEN
345 CALL wrf_message ( 'ReconcileTimes: inconsistent couplingIntervals. Using first.' )
346 couplingIntervals(i) = couplingInterval
351 startTimes = startTime
353 END SUBROUTINE ReconcileTimes
357 !TODO: Eliminate this once this information can be derived via other
359 SUBROUTINE AttachDecompToState( state, &
360 ids, ide, jds, jde, kds, kde, &
361 ims, ime, jms, jme, kms, kme, &
362 ips, ipe, jps, jpe, kps, kpe, &
364 TYPE(ESMF_State), INTENT(INOUT) :: state
365 INTEGER, INTENT(IN ) :: ids, ide, jds, jde, kds, kde
366 INTEGER, INTENT(IN ) :: ims, ime, jms, jme, kms, kme
367 INTEGER, INTENT(IN ) :: ips, ipe, jps, jpe, kps, kpe
368 INTEGER, INTENT(IN ) :: domdesc
369 LOGICAL, INTENT(IN ) :: bdy_mask(4)
372 ! big enough to hold the integer values listed above
373 INTEGER(ESMF_KIND_I4) :: intvals(19)
374 ! big enough to hold the logical values listed above
375 ! TYPE(ESMF_Logical) :: logvals(4)
376 logical :: logvals(4)
379 ! Usually, when writing an API for a target language, it is considered
380 ! good practice to use native types of the target language in the
383 DO i = 1, SIZE(bdy_mask)
384 IF (bdy_mask(i)) THEN
388 CALL ESMF_AttributeSet(state, 'DecompositionLogicals', logvals, itemCount=SIZE(logvals), rc=rc)
389 IF ( rc /= ESMF_SUCCESS) THEN
390 CALL wrf_error_fatal ( 'ESMF_AttributeSet(DecompositionLogicals) failed' )
411 intvals(19) = domdesc
412 CALL ESMF_AttributeSet(state, 'DecompositionIntegers', intvals, itemCount=SIZE(intvals), rc=rc)
413 IF ( rc /= ESMF_SUCCESS) THEN
414 CALL wrf_error_fatal ( 'ESMF_AttributeSet(DecompositionIntegers) failed' )
416 END SUBROUTINE AttachDecompToState
420 !TODO: Eliminate this once this information can be derived via other
422 SUBROUTINE GetDecompFromState( state, &
423 ids, ide, jds, jde, kds, kde, &
424 ims, ime, jms, jme, kms, kme, &
425 ips, ipe, jps, jpe, kps, kpe, &
427 TYPE(ESMF_State), INTENT(INOUT) :: state
428 INTEGER, INTENT( OUT) :: ids, ide, jds, jde, kds, kde
429 INTEGER, INTENT( OUT) :: ims, ime, jms, jme, kms, kme
430 INTEGER, INTENT( OUT) :: ips, ipe, jps, jpe, kps, kpe
431 INTEGER, INTENT( OUT) :: domdesc
432 LOGICAL, INTENT( OUT) :: bdy_mask(4)
435 ! big enough to hold the integer values listed above
436 INTEGER(ESMF_KIND_I4) :: intvals(19)
437 ! big enough to hold the logical values listed above
438 logical :: logvals(4)
439 integer :: thecount ! ah ah ah
442 thecount = SIZE(logvals)
443 CALL ESMF_AttributeGet(state, 'DecompositionLogicals', logvals, itemCount=thecount, rc=rc)
444 IF ( rc /= ESMF_SUCCESS) THEN
445 CALL wrf_error_fatal ( 'ESMF_AttributeGet(DecompositionLogicals) failed' )
447 ! Usually, when writing an API for a target language, it is considered
448 ! good practice to use native types of the target language in the
451 DO i = 1, SIZE(logvals)
452 IF (logvals(i) ) THEN
457 thecount = SIZE(intvals)
458 CALL ESMF_AttributeGet(state, 'DecompositionIntegers', intvals, itemCount=thecount, rc=rc)
459 IF ( rc /= ESMF_SUCCESS) THEN
460 CALL wrf_error_fatal ( 'ESMF_AttributeGet(DecompositionIntegers) failed' )
480 domdesc = intvals(19)
481 END SUBROUTINE GetDecompFromState
485 END MODULE module_metadatautils
489 MODULE module_wrf_component_top
491 ! This module defines wrf_component_init1(), wrf_component_init2(),
492 ! wrf_component_run(), and wrf_component_finalize() routines that are called
493 ! when WRF is run as an ESMF component.
497 USE module_wrf_top, ONLY : wrf_init, wrf_run, wrf_finalize
498 USE module_domain, ONLY : head_grid, get_ijk_from_grid
499 USE module_state_description
502 USE module_esmf_extensions
503 USE module_metadatautils, ONLY: AttachTimesToState, AttachDecompToState
509 ! everything is private by default
512 ! Public entry points
513 PUBLIC wrf_component_init1
514 PUBLIC wrf_component_init2
515 PUBLIC wrf_component_run
516 PUBLIC wrf_component_finalize
519 CHARACTER (ESMF_MAXSTR) :: str
524 SUBROUTINE wrf_component_init1( gcomp, importState, exportState, clock, rc )
525 TYPE(ESMF_GridComp), TARGET, INTENT(INOUT) :: gcomp
526 TYPE(ESMF_State), TARGET, INTENT(INOUT) :: importState
527 TYPE(ESMF_State), TARGET, INTENT(INOUT) :: exportState
528 TYPE(ESMF_Clock), TARGET, INTENT(INOUT) :: clock
533 INTEGER, INTENT( OUT) :: rc
535 ! WRF component init routine, phase 1. Passes relevant coupling
536 ! information back as metadata on exportState.
540 ! importState Importstate
541 ! exportState Exportstate
542 ! clock External clock
543 ! rc Return code; equals ESMF_SUCCESS if there are no errors,
544 ! otherwise ESMF_FAILURE.
546 !TODO: Note that much of the decomposition-related meta-data attached to the
547 !TODO: exportState are WRF-specific and are only useful if other components
548 !TODO: want to re-use the WRF IOAPI with the same decomposition as the WRF
549 !TODO: model. This is true for the simple WRF+CPL+SST test case, but will
550 !TODO: not be in general. Of course other components are free to ignore this
554 TYPE(ESMF_GridComp), POINTER :: p_gcomp
555 TYPE(ESMF_State), POINTER :: p_importState
556 TYPE(ESMF_State), POINTER :: p_exportState
557 TYPE(ESMF_Clock), POINTER :: p_clock
559 TYPE(ESMF_Time) :: startTime
560 TYPE(ESMF_Time) :: stopTime
561 TYPE(ESMF_TimeInterval) :: couplingInterval
562 ! decomposition hackery
563 INTEGER :: ids, ide, jds, jde, kds, kde
564 INTEGER :: ims, ime, jms, jme, kms, kme
565 INTEGER :: ips, ipe, jps, jpe, kps, kpe
567 LOGICAL :: bdy_mask(4)
568 CHARACTER(LEN=256) :: couplingIntervalString
573 p_importState => importState
574 p_exportState => exportState
576 ! NOTE: It will be possible to remove this call once ESMF supports
577 ! interfaces ESMF_ClockGetCurrent(), ESMF_ImportStateGetCurrent(),
578 ! ESMF_ExportStateGetCurrent(), and ESMF_GridCompGetCurrent().
579 CALL ESMF_SetCurrent( gcomp=p_gcomp, importState=p_importState, &
580 exportState=p_exportState, clock=p_clock )
583 CALL ESMF_VMGetCurrent(vm, rc=rc)
584 IF ( rc /= ESMF_SUCCESS ) THEN
585 CALL wrf_error_fatal ( 'wrf_component_init1: ESMF_VMGetCurrent failed' )
587 CALL ESMF_VMGet(vm, mpiCommunicator=mpicomtmp, rc=rc)
588 IF ( rc /= ESMF_SUCCESS ) THEN
589 CALL wrf_error_fatal ( 'wrf_component_init1: ESMF_VMGet failed' )
591 CALL wrf_set_dm_communicator( mpicomtmp )
594 ! Call WRF "init" routine, which, for a DM_PARALLEL run, will recognize
595 ! that ESMF has already called MPI_INIT and respond appropriately.
596 CALL wrf_init( no_init1=.TRUE. )
598 ! For now, use settings from WRF component intialization to set up
599 ! top-level clock. Per suggestion from ESMF Core team, these are passed
600 ! back as attributes on exportState.
601 CALL wrf_clockprint( 100, head_grid%domain_clock, &
602 'DEBUG wrf_component_init1(): head_grid%domain_clock,' )
603 CALL ESMF_ClockGet(head_grid%domain_clock, startTime=startTime, &
604 stopTime=stopTime, rc=rc)
605 IF ( rc /= ESMF_SUCCESS ) THEN
606 CALL wrf_error_fatal ( 'wrf_component_init1: ESMF_ClockGet failed' )
608 CALL wrf_debug( 500, 'DEBUG wrf_component_init1(): before wrf_findCouplingInterval' )
609 CALL wrf_findCouplingInterval( startTime, stopTime, couplingInterval )
610 CALL wrf_debug( 500, 'DEBUG wrf_component_init1(): after wrf_findCouplingInterval' )
611 CALL ESMF_TimeIntervalGet( couplingInterval, TimeString=couplingIntervalString, &
613 IF ( rc /= ESMF_SUCCESS ) THEN
614 CALL wrf_error_fatal ( 'wrf_component_init1: ESMF_TimeIntervalGet failed' )
616 CALL wrf_debug( 100, 'DEBUG wrf_component_init1(): couplingInterval = '//TRIM(couplingIntervalString) )
617 CALL AttachTimesToState( exportState, startTime, stopTime, couplingInterval )
618 CALL wrf_getDecompInfo( ids, ide, jds, jde, kds, kde, &
619 ims, ime, jms, jme, kms, kme, &
620 ips, ipe, jps, jpe, kps, kpe, &
622 CALL AttachDecompToState( exportState, &
623 ids, ide, jds, jde, kds, kde, &
624 ims, ime, jms, jme, kms, kme, &
625 ips, ipe, jps, jpe, kps, kpe, &
627 CALL AttachDecompToState( importState, &
628 ids, ide, jds, jde, kds, kde, &
629 ims, ime, jms, jme, kms, kme, &
630 ips, ipe, jps, jpe, kps, kpe, &
633 END SUBROUTINE wrf_component_init1
637 SUBROUTINE wrf_component_init2( gcomp, importState, exportState, clock, rc )
638 TYPE(ESMF_GridComp), TARGET, INTENT(INOUT) :: gcomp
639 TYPE(ESMF_State), TARGET, INTENT(INOUT) :: importState
640 TYPE(ESMF_State), TARGET, INTENT(INOUT) :: exportState
641 TYPE(ESMF_Clock), TARGET, INTENT(INOUT) :: clock
642 INTEGER, INTENT( OUT) :: rc
644 ! WRF component init routine, phase 2. Initializes importState and
649 ! importState Importstate
650 ! exportState Exportstate
651 ! clock External clock
652 ! rc Return code; equals ESMF_SUCCESS if there are no errors,
653 ! otherwise ESMF_FAILURE.
657 TYPE(ESMF_GridComp), POINTER :: p_gcomp
658 TYPE(ESMF_State), POINTER :: p_importState
659 TYPE(ESMF_State), POINTER :: p_exportState
660 TYPE(ESMF_Clock), POINTER :: p_clock
662 TYPE(ESMF_Time) :: startTime
663 TYPE(ESMF_Time) :: stopTime
664 TYPE(ESMF_TimeInterval) :: couplingInterval
665 ! decomposition hackery
666 INTEGER :: ids, ide, jds, jde, kds, kde
667 INTEGER :: ims, ime, jms, jme, kms, kme
668 INTEGER :: ips, ipe, jps, jpe, kps, kpe
670 LOGICAL :: bdy_mask(4)
671 INTEGER :: itemCount, i
672 TYPE(ESMF_StateIntent_Flag) :: stateintent
673 CHARACTER (ESMF_MAXSTR) :: statename
674 CHARACTER (ESMF_MAXSTR), ALLOCATABLE :: itemNames(:)
675 TYPE(ESMF_StateItem_Flag), ALLOCATABLE :: itemTypes(:)
677 CALL wrf_debug ( 100, 'wrf_component_init2(): begin' )
680 CALL ESMF_StateGet( exportState, itemCount=itemCount, &
681 stateintent=stateintent, rc=rc )
682 IF ( rc /= ESMF_SUCCESS ) THEN
683 CALL wrf_error_fatal("wrf_component_init2: ESMF_StateGet(exportState) failed" )
685 WRITE (str,*) 'wrf_component_init2: exportState itemCount = ', itemCount
686 CALL wrf_debug ( 100 , TRIM(str) )
687 IF ( stateintent /= ESMF_STATEINTENT_EXPORT ) THEN
688 CALL wrf_error_fatal("wrf_component_init2: exportState is not an export state" )
692 CALL ESMF_StateGet( importState, itemCount=itemCount, &
693 stateintent=stateintent, rc=rc )
694 IF ( rc /= ESMF_SUCCESS ) THEN
695 CALL wrf_error_fatal("wrf_component_init2: ESMF_StateGet(importState) failed" )
697 WRITE (str,*) 'wrf_component_init2: importState itemCount = ', itemCount
698 CALL wrf_debug ( 100 , TRIM(str) )
699 IF ( stateintent /= ESMF_STATEINTENT_IMPORT ) THEN
700 CALL wrf_error_fatal("wrf_component_init2: importState is not an import state" )
704 p_importState => importState
705 p_exportState => exportState
707 ! NOTE: It will be possible to remove this call once ESMF supports
708 ! interfaces ESMF_ClockGetCurrent(), ESMF_ImportStateGetCurrent(),
709 ! ESMF_ExportStateGetCurrent(), and ESMF_GridCompGetCurrent().
710 CALL ESMF_SetCurrent( gcomp=p_gcomp, importState=p_importState, &
711 exportState=p_exportState, clock=p_clock )
713 ! populate ESMF import and export states
714 CALL wrf_state_populate( rc )
716 CALL wrf_error_fatal ( 'wrf_component_init2: wrf_state_populate failed' )
719 ! examine importState
720 WRITE (str,*) 'wrf_component_init2: EXAMINING importState...'
721 CALL wrf_debug ( 100 , TRIM(str) )
722 CALL ESMF_StateGet( importState, itemCount=itemCount, &
723 stateintent=stateintent, name=statename, rc=rc )
724 IF ( rc /= ESMF_SUCCESS ) THEN
725 CALL wrf_error_fatal("wrf_component_init2: ESMF_StateGet(importState) failed B" )
727 IF ( stateintent /= ESMF_STATEINTENT_IMPORT ) THEN
728 CALL wrf_error_fatal("wrf_component_init2: importState is not an import state" )
730 WRITE (str,*) 'wrf_component_init2: importState <',TRIM(statename), &
731 '> itemCount = ', itemCount
732 CALL wrf_debug ( 100 , TRIM(str) )
733 ALLOCATE ( itemNames(itemCount), itemTypes(itemCount) )
734 CALL ESMF_StateGet( importState, itemNameList=itemNames, &
735 itemtypeList=itemTypes, rc=rc )
736 IF ( rc /= ESMF_SUCCESS ) THEN
737 CALL wrf_error_fatal("wrf_component_init2: ESMF_StateGet(importState) failed C" )
740 IF ( itemTypes(i) == ESMF_STATEITEM_FIELD ) THEN
741 WRITE(str,*) 'wrf_component_init2: importState contains field <',TRIM(itemNames(i)),'>'
742 CALL wrf_debug ( 100 , TRIM(str) )
745 DEALLOCATE ( itemNames, itemTypes )
746 WRITE (str,*) 'wrf_component_init2: DONE EXAMINING importState...'
747 CALL wrf_debug ( 100 , TRIM(str) )
749 ! examine exportState
750 WRITE (str,*) 'wrf_component_init2: EXAMINING exportState...'
751 CALL wrf_debug ( 100 , TRIM(str) )
752 CALL ESMF_StateGet( exportState, itemCount=itemCount, &
753 stateintent=stateintent, name=statename, rc=rc )
754 IF ( rc /= ESMF_SUCCESS ) THEN
755 CALL wrf_error_fatal("wrf_component_init2: ESMF_StateGet(exportState) failed B" )
757 IF ( stateintent /= ESMF_STATEINTENT_EXPORT ) THEN
758 CALL wrf_error_fatal("wrf_component_init2: exportState is not an export state" )
760 WRITE (str,*) 'wrf_component_init2: exportState <',TRIM(statename), &
761 '> itemCount = ', itemCount
762 CALL wrf_debug ( 100 , TRIM(str) )
763 ALLOCATE ( itemNames(itemCount), itemTypes(itemCount) )
764 CALL ESMF_StateGet( exportState, itemNameList=itemNames, &
765 itemtypeList=itemTypes, rc=rc )
766 IF ( rc /= ESMF_SUCCESS ) THEN
767 CALL wrf_error_fatal("wrf_component_init2: ESMF_StateGet(exportState) failed C" )
770 IF ( itemTypes(i) == ESMF_STATEITEM_FIELD ) THEN
771 WRITE(str,*) 'wrf_component_init2: exportState contains field <',TRIM(itemNames(i)),'>'
772 CALL wrf_debug ( 100 , TRIM(str) )
775 DEALLOCATE ( itemNames, itemTypes )
776 WRITE (str,*) 'wrf_component_init2: DONE EXAMINING exportState...'
777 CALL wrf_debug ( 100 , TRIM(str) )
779 CALL wrf_debug ( 100, 'DEBUG wrf_component_init2(): end' )
781 END SUBROUTINE wrf_component_init2
785 SUBROUTINE wrf_component_run( gcomp, importState, exportState, clock, rc )
786 TYPE(ESMF_GridComp), TARGET, INTENT(INOUT) :: gcomp
787 TYPE(ESMF_State), TARGET, INTENT(INOUT) :: importState, exportState
788 TYPE(ESMF_Clock), TARGET, INTENT(INOUT) :: clock
789 INTEGER, INTENT( OUT) :: rc
791 ! WRF component run routine.
795 ! importState Importstate
796 ! exportState Exportstate
797 ! clock External clock
798 ! rc Return code; equals ESMF_SUCCESS if there are no errors,
799 ! otherwise ESMF_FAILURE.
803 TYPE(ESMF_GridComp), POINTER :: p_gcomp
804 TYPE(ESMF_State), POINTER :: p_importState
805 TYPE(ESMF_State), POINTER :: p_exportState
806 TYPE(ESMF_Clock), POINTER :: p_clock
808 TYPE(ESMF_Time) :: currentTime, nextTime
809 TYPE(ESMF_TimeInterval) :: runLength ! how long to run in this call
810 CHARACTER(LEN=256) :: timeStr
812 CALL wrf_debug ( 100 , 'DEBUG wrf_component_run(): begin' )
815 p_importState => importState
816 p_exportState => exportState
818 ! NOTE: It will be possible to remove this call once ESMF supports
819 ! interfaces ESMF_ClockGetCurrent(), ESMF_ImportStateGetCurrent(),
820 ! ESMF_ExportStateGetCurrent(), and ESMF_GridCompGetCurrent().
821 CALL ESMF_SetCurrent( gcomp=p_gcomp, importState=p_importState, &
822 exportState=p_exportState, clock=p_clock )
824 ! connect ESMF clock with WRF domain clock
825 CALL ESMF_ClockGet( clock, currTime=currentTime, timeStep=runLength, rc=rc )
826 IF ( rc /= ESMF_SUCCESS ) THEN
827 CALL wrf_error_fatal ( 'wrf_component_run: ESMF_ClockGet failed' )
829 CALL wrf_clockprint(100, clock, &
830 'DEBUG wrf_component_run(): clock,')
831 nextTime = currentTime + runLength
832 head_grid%start_subtime = currentTime
833 head_grid%stop_subtime = nextTime
834 CALL wrf_timetoa ( head_grid%start_subtime, timeStr )
835 WRITE (str,*) 'wrf_component_run: head_grid%start_subtime ',TRIM(timeStr)
836 CALL wrf_debug ( 100 , TRIM(str) )
837 CALL wrf_timetoa ( head_grid%stop_subtime, timeStr )
838 WRITE (str,*) 'wrf_component_run: head_grid%stop_subtime ',TRIM(timeStr)
839 CALL wrf_debug ( 100 , TRIM(str) )
841 ! Call WRF "run" routine
842 CALL wrf_debug ( 100 , 'DEBUG wrf_component_run(): calling wrf_run()' )
844 CALL wrf_debug ( 100 , 'DEBUG wrf_component_run(): back from wrf_run()' )
846 CALL wrf_debug ( 100 , 'DEBUG wrf_component_run(): end' )
848 END SUBROUTINE wrf_component_run
852 SUBROUTINE wrf_component_finalize( gcomp, importState, exportState, clock, rc )
853 TYPE(ESMF_GridComp), TARGET, INTENT(INOUT) :: gcomp
854 TYPE(ESMF_State), TARGET, INTENT(INOUT) :: importState, exportState
855 TYPE(ESMF_Clock), TARGET, INTENT(INOUT) :: clock
856 INTEGER, INTENT( OUT) :: rc
858 ! WRF component finalize routine.
862 ! importState Importstate
863 ! exportState Exportstate
864 ! clock External clock
865 ! rc Return code; equals ESMF_SUCCESS if there are no errors,
866 ! otherwise ESMF_FAILURE.
870 TYPE(ESMF_GridComp), POINTER :: p_gcomp
871 TYPE(ESMF_State), POINTER :: p_importState
872 TYPE(ESMF_State), POINTER :: p_exportState
873 TYPE(ESMF_Clock), POINTER :: p_clock
876 p_importState => importState
877 p_exportState => exportState
879 ! NOTE: It will be possible to remove this call once ESMF supports
880 ! interfaces ESMF_ClockGetCurrent(), ESMF_ImportStateGetCurrent(),
881 ! ESMF_ExportStateGetCurrent(), and ESMF_GridCompGetCurrent().
882 CALL ESMF_SetCurrent( gcomp=p_gcomp, importState=p_importState, &
883 exportState=p_exportState, clock=p_clock )
885 ! Call WRF "finalize" routine, suppressing call to MPI_FINALIZE so
886 ! ESMF can do it (if needed) during ESMF_Finalize().
887 CALL wrf_finalize( no_shutdown=.TRUE. )
891 END SUBROUTINE wrf_component_finalize
895 SUBROUTINE wrf_findCouplingInterval( startTime, stopTime, couplingInterval )
896 TYPE(ESMF_Time), INTENT(IN ) :: startTime
897 TYPE(ESMF_Time), INTENT(IN ) :: stopTime
898 TYPE(ESMF_TimeInterval), INTENT( OUT) :: couplingInterval
900 ! WRF convenience routine for deducing coupling interval. The startTime
901 ! and stopTime arguments are only used for determining a default value
902 ! when coupling is not actually being done.
905 ! startTime start time
907 ! couplingInterval coupling interval
910 LOGICAL :: foundcoupling
913 ! external function prototype
914 INTEGER, EXTERNAL :: use_package
916 ! deduce coupling time-step
917 foundcoupling = .FALSE.
918 !TODO: This bit just finds the FIRST case and extracts coupling interval...
919 !TODO: Add error-checking for over-specification.
920 !TODO: Add support for multiple coupling intervals later...
921 !TODO: Add support for coupling that does not begin immediately later...
922 !TODO: Get rid of duplication once I/O refactoring is finished (and
923 !TODO: auxio streams can be addressed via index).
925 #include "med_find_esmf_coupling.inc"
927 ! look for erroneous use of io_form...
928 CALL nl_get_io_form_restart( 1, io_form )
929 IF ( use_package( io_form ) == IO_ESMF ) THEN
930 CALL wrf_error_fatal ( 'wrf_findCouplingInterval: ERROR: ESMF cannot be used for WRF restart I/O' )
932 CALL nl_get_io_form_input( 1, io_form )
933 IF ( use_package( io_form ) == IO_ESMF ) THEN
934 CALL wrf_error_fatal ( 'wrf_findCouplingInterval: ERROR: ESMF cannot be used for WRF input' )
936 CALL nl_get_io_form_history( 1, io_form )
937 IF ( use_package( io_form ) == IO_ESMF ) THEN
938 CALL wrf_error_fatal ( 'wrf_findCouplingInterval: ERROR: ESMF cannot be used for WRF history output' )
940 CALL nl_get_io_form_boundary( 1, io_form )
941 IF ( use_package( io_form ) == IO_ESMF ) THEN
942 CALL wrf_error_fatal ( 'wrf_findCouplingInterval: ERROR: ESMF cannot be used for WRF boundary I/O' )
945 ! If nobody uses IO_ESMF, then default is to run WRF all the way to
947 IF ( .NOT. foundcoupling ) THEN
948 couplingInterval = stopTime - startTime
949 call wrf_debug ( 1, 'WARNING: ESMF coupling not used in this WRF run' )
952 END SUBROUTINE wrf_findCouplingInterval
956 SUBROUTINE wrf_getDecompInfo( ids, ide, jds, jde, kds, kde, &
957 ims, ime, jms, jme, kms, kme, &
958 ips, ipe, jps, jpe, kps, kpe, &
960 INTEGER, INTENT(OUT) :: ids, ide, jds, jde, kds, kde
961 INTEGER, INTENT(OUT) :: ims, ime, jms, jme, kms, kme
962 INTEGER, INTENT(OUT) :: ips, ipe, jps, jpe, kps, kpe
963 INTEGER, INTENT(OUT) :: domdesc
964 LOGICAL, INTENT(OUT) :: bdy_mask(4)
966 ! WRF convenience routine for deducing decomposition information.
967 !TODO: Note that domdesc is meaningful only for SPMD alternating event loops.
968 !TODO: For concurrent operation (SPMD or MPMD), we will need to create a new
969 !TODO: "domdesc" suitable for the task layout of the SST component. For
970 !TODO: MPMD alternating event loops, we will need to serialize domdesc and
971 !TODO: store it as metadata within the export state. Similar arguments apply
972 !TODO: to [ij][mp][se] and bdy_mask.
975 ! ids, ide, jds, jde, kds, kde Domain extent.
976 ! ims, ime, jms, jme, kms, kme Memory extent.
977 ! ips, ipe, jps, jpe, kps, kpe Patch extent.
978 ! domdesc Domain descriptor for external
979 ! distributed-memory communication
980 ! package (opaque to WRF).
981 ! bdy_mask Boundary mask flags indicating which
982 ! domain boundaries are on this task.
984 ! extract decomposition information from head_grid
985 CALL get_ijk_from_grid( head_grid , &
986 ids, ide, jds, jde, kds, kde, &
987 ims, ime, jms, jme, kms, kme, &
988 ips, ipe, jps, jpe, kps, kpe )
991 ! with version 3 of ESMF's staggering concepts, WRF's non-staggered grid is equivalent to
992 ! esmf's 'exclusive' region -- that is the set of points that are owned by the 'DE' (eyeroll)
993 ! WRF, on the other hand, is returning the 'staggered' dimensions here. So convert to the
994 ! unstaggered dims before returning.
995 ! Don't bother with vertical dimension for the time being, since we're only doing 2D coupling.
997 ide = ide-1 ; ipe = MIN(ide,ipe)
998 jde = jde-1 ; jpe = MIN(jde,jpe)
1001 ! with version 4 I have no damned clue at this writing... just random shots for now
1002 ! see if this works.
1003 ipe = MIN(ide-1,ipe)
1004 jpe = MIN(jde-1,jpe)
1007 domdesc = head_grid%domdesc
1008 bdy_mask = head_grid%bdy_mask
1009 END SUBROUTINE wrf_getDecompInfo
1012 SUBROUTINE wrf_state_populate( ierr )
1014 USE module_domain, ONLY : domain
1015 USE module_io_domain
1017 USE module_configure, ONLY : grid_config_rec_type, model_to_grid_config_rec
1018 USE module_bc_time_utilities
1023 ! Populate WRF import and export states from Registry-generated code.
1024 ! For now, only head_grid can be coupled.
1027 !TODO: Extend later to include child
1028 !TODO: domains, possibly via nested ESMF_State's.
1031 INTEGER, INTENT(OUT) :: ierr
1033 TYPE(domain), POINTER :: grid
1034 TYPE(grid_config_rec_type) :: config_flags
1035 INTEGER :: stream, idum1, idum2, io_form
1036 CHARACTER*80 :: fname, n2
1037 ! external function prototype
1038 INTEGER, EXTERNAL :: use_package
1040 ! for now support coupling to head_grid only
1042 ! TODO: Use actual grid via current_grid%id via something like this...
1043 ! IF ( current_grid_set ) THEN
1044 ! grid => current_grid
1049 CALL model_to_grid_config_rec ( grid%id , model_config_rec , config_flags )
1050 CALL set_scalar_indices_from_config ( grid%id , idum1 , idum2 )
1055 #include "med_open_esmf_calls.inc"
1057 END SUBROUTINE wrf_state_populate
1059 END MODULE module_wrf_component_top
1063 MODULE module_wrf_setservices
1065 ! This module defines WRF "Set Services" method wrf_register()
1066 ! used for ESMF coupling.
1069 USE module_wrf_component_top, ONLY: wrf_component_init1, &
1070 wrf_component_init2, &
1071 wrf_component_run, &
1072 wrf_component_finalize
1077 ! everything is private by default
1080 ! Public entry point for ESMF_GridCompSetServices()
1084 CHARACTER (ESMF_MAXSTR) :: str
1089 SUBROUTINE wrf_register(gcomp, rc)
1090 TYPE(ESMF_GridComp), INTENT(INOUT) :: gcomp
1091 INTEGER, INTENT(OUT) :: rc
1094 ! WRF_register - Externally visible registration routine
1096 ! User-supplied SetServices routine.
1097 ! The Register routine sets the subroutines to be called
1098 ! as the init, run, and finalize routines. Note that these are
1099 ! private to the module.
1101 ! The arguments are:
1103 ! rc Return code; equals ESMF_SUCCESS if there are no errors,
1104 ! otherwise ESMF_FAILURE.
1108 ! Register the callback routines.
1109 call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
1110 wrf_component_init1, phase=1, rc=rc)
1111 IF ( rc /= ESMF_SUCCESS) THEN
1112 CALL wrf_error_fatal ( 'wrf_register: ESMF_GridCompSetEntryPoint(wrf_component_init1) failed' )
1114 call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
1115 wrf_component_init2, phase=2, rc=rc)
1116 IF ( rc /= ESMF_SUCCESS) THEN
1117 CALL wrf_error_fatal ( 'wrf_register: ESMF_GridCompSetEntryPoint(wrf_component_init2) failed' )
1119 call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_RUN, &
1120 wrf_component_run, rc=rc)
1121 IF ( rc /= ESMF_SUCCESS) THEN
1122 CALL wrf_error_fatal ( 'wrf_register: ESMF_GridCompSetEntryPoint(wrf_component_run) failed' )
1124 call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_FINALIZE, &
1125 wrf_component_finalize, rc=rc)
1126 IF ( rc /= ESMF_SUCCESS) THEN
1127 CALL wrf_error_fatal ( 'wrf_register: ESMF_GridCompSetEntryPoint(wrf_component_finalize) failed' )
1129 PRINT *,'WRF: Registered Initialize, Run, and Finalize routines'
1131 END SUBROUTINE wrf_register
1133 END MODULE module_wrf_setservices