To understand the details of the Coupler's functionality, it is useful to have a basic understanding of the computer code that is the Coupler. To that end, pseudo-code is shown below. If one wishes to modify the Coupler source code, it is strongly recommended that one first study this section in conjunction with studying the source code file, main.F90. This should provide a good overview of how the Coupler works; a necessary pre-requisite for successful code modification. The actual source code is 99.9% pure Fortran 90.
A variable naming convention has been adopted to help organize and identify the literally hundreds of state and flux fields managed by the Coupler. Understanding this naming convention is a prerequisite for understanding the pseudo-code below.State Variables
Model state variables are denoted Sx, where x denotes the corresponding component model: * Sa = atm state variables, e.g. atm wind velocity * Si = ice state variables, e.g. ice temperature * Sl = lnd state variables, e.g. lnd albedo * So = ocn state variables, e.g. ocn SST * Ss = all surface states merged together, e.g. global surface temperature Next, a suffix _x indicates what model grid the states reside on: * Sa_a: atm states on atm grid * Sa_o: atm states on ocn gridFlux Fields
Input flux means fluxes given by the Coupler to a model. Output flux means fluxes computed within a model and given to the Coupler. All input fluxes for one model were either computed by the Coupler or were the output flux of another model. In general, a given flux field between any two component models may have been computed in one of three places: within either of the two models or within the Coupler. One function of the Coupler is to gather, merge, sum, and/or time-average the various component flux fields from various sources and form a set of complete input fluxes for each component model. This gathering and merging process will generally involve mapping flux fields between various model grids and combining like fields from several grids onto one grid. A summation might be required, e.g., net heat flux = solar + latent + sensible + longwave. Also, for some flux fields the Coupler might be required to form time-averaged quantities. Thus component fluxes are mapped, merged, summed, and/or time-averaged by the Coupler in order to form complete input fluxes for the models. Flux fields are denoted Fxyz, where xy denotes the two model between which a quantity is being fluxed, and z denotes the model which computed the flux (i.e. it is an output flux of model z). Component fluxes that are gathered, merged, summed, and/or time--averaged to form the complete input fluxes are: * Faia = atm/ice flux, computed by atm, e.g. precipitation * Faii = atm/ice flux, computed by ice, e.g. sensible heat flux * Fala = atm/lnd flux, computed by atm, e.g. precipitation * Fall = atm/lnd flux, computed by lnd, e.g. sensible heat flux * Faoc = atm/ocn flux, computed by cpl, e.g. momentum flux * Faoa = atm/ocn flux, computed by atm, e.g. precipitation * Fioo = ice/ocn flux, computed by ocn, e.g. ice formed within the ocn * Fioi = ice/ocn flux, computed by ice, e.g. penetrating shortwave radiation * Flol = lnd/ocn flux, computed by lnd, e.g. river runoff Complete input fluxes (an "a" prefix denotes a daily average): * Faxx = all atm input fluxes: a map/merge/sum of: Faoc, Faii, Fall * Flxx = all lnd input fluxes: a map/merge/sum of: Fala * Foxx = all ocn input fluxes: a map/merge/sum of: Faoc, Faoa, Fioi, Flol * aFoxx = a time average of: Foxx * Fixx = all ice input fluxes: a map/merge/sum of: Faia, Fioo Finally, just like the state variables above, a suffix _x indicates what model grid the fluxes reside on: * Faoa_a: atm/ocn fluxes, computed by the atm, on the atm grid * Faoa_o: atm/ocn fluxes, computed by the atm, on the ocn gridDomain Maps
Mapping between domains is implemented by matrix multiplies. Generally there are different maps for state fields vs. flux fields, as state fields maps are generally smoother (eg. bilinear) whereas flux field maps must be conservative (eg. area averaging, aka Riemann sum integrals). In the case of mapping between identical domains, the map would be the identity map. The necessary mapping matrices are: * map_Fa2i: map for fluxes, atm -> ice * map_Sa2i: map for states, atm -> ice * map_Fa2l: map for fluxes, atm -> lnd * map_Sa2l: map for states, atm -> lnd * map_Fa2o: map for fluxes, atm -> ocn * map_Sa2o: map for states, atm -> ocn * map_Fi2a: map for fluxes, ice -> atm * map_Si2a: map for states, ice -> atm etc.
Notice that the Coupler code is configured for a particular time coordination scheme. Model time coordination involves two communication intervals, with the longer interval being an integer multiple of the shorter interval. The atmosphere, ice, and land models communicate once per short interval while the ocean model communicates once per long interval. Also, one day (24 hours) is an integer multiple of the longer communication interval. Typically the longer interval is exactly one day, while the shorter interval is several hours or less. While this configuration is hard-coded within the Coupler, its modular design facilitates code modifications to implement alternate configurations. A variety of time coordination schemes can be, and have been, implemented by rearranging subroutine calls at the highest level (within the main program), requiring a minimal amount of code modifications or new code. PROGRAM main call initial ! read input namelist call msg_atm_init ! exchange spatial & temporal grid info with atm model call msg_ice_init ! exchange spatial & temporal grid info with ice model call msg_lnd_init ! exchange spatial & temporal grid info with lnd model call msg_ocn_init ! exchange spatial & temporal grid info with ocn model !--- read restart file --- call restart ('read' , Sa_a , Faia_a , Fala_a , Faoa_a , & Sl_l , Fall_l , Falo_l , & Si_i , Faii_i , Fioi_i , & So_o , Fioo_o ,aFoxx_o ) m = ncpl_a/ncpl_o ! determine number of atm messages per ocn message DO WHILE ( current_date < stop_date ) DO n=0,ncpl_a-1 !--- send tavg inputs to ocn, start new tavg summation --- if ( mod(n,m) == 0 ) then call msg_ocn_send (aFoxx_o) call tavg-zero (aFoxx_o) ! start new time average end if !--- map atm states/fluxes to lnd, send msg to lnd --- call map (map_Sa2l, Sa_a , Sa_l ) call map (map_Fa2l, Fala_a ,Fala_l ) !lnds call msg_lnd_send ( Fala_l , Sa_l ) !--- map atm states/fluxes to ice grid --- call map (map_Sa2i, Sa_a , Sa_i ) call map (map_Fa2i, Faia_a , Faia_i ) !--- send msg to ice --- !ices call msg_ice_send ( Sa_i , So_i, Faia_i, Fioo_i ) !--- prepare instantaneous ocn inputs --- call map (map_Sa2o, Sa_a , Sa_o ) call map (map_Fa2o, Faoa_a , Faoa_o ) call map (map_Fl2o, Flol_l , Flol_o ) call flux_solar ( Faoa_o, So_o, Faoc_o ) ! compute net short-wave !--- "send" msg to ocn (add instantaneous data to t-avg) --- !ocns call mrg_ocn ( Faoa_o, Faoc_o, Fioi_o, Flol_o, Foxx_o) call tavg-sum ( Foxx_o, aFoxx_o) !--- compute ocean albedos and Faoc fluxes --- !ocnr call flux_albedo ( So_o ) ! update ocn state ~ "receive" call flux_ao ( Sa_o, So_o, Faoc_o ) !--- map ocn states/fluxes to atm --- call map( map_Fo2a, Faoc_o, Faoc_a ) call map( map_So2a, So_o, So_a ) !icer !--- receive ice outputs --- call msg_ice_recv (Si_i ,Faii_i, Fioi_i ) !--- map ice states/fluxes to atm & ocn grid --- call map (map_Fi2a, Faii_i, Faii_a ) call map (map_Si2a, Si_i, Si_a ) call map (map_Fi2o, Fioi_i, Fioi_o ) call map (map_Si2o, Si_i, Si_o ) !lndr !--- recv new lnd data --- call msg_lnd_recv (Sl_l, Fall_l, Flol_l ) !--- map lnd states & fluxes to atm --- call map (map_Fl2a, Fall_l, Fall_a ) call map (map_Sl2a, Sl_l, Sl_a ) !--- merge atm states & fluxes --- call mrg_atm (Faii_a, Fall_a, Faoc_a, Faxx_a) call mrg_atm ( Si_a, Sl_a, So_a, Ss_a) !atms !--- send data to atm --- call msg_atm_send (Faxx_a, Ss_a ) !--- add data to history file --- call history () if ( mod(n+1,m) == 0 ) then !--- receive ocn outputs --- call msg_ocn_recv (So_o , Fioo_o) !--- map ocn to ice --- call map (map_So2i, So_o, So_i ) call map (map_Fo2i, Fioo_o, Fioo_i ) !--- form tavg of ocn inputs summation--- call tavg-avg(aFoxx_o,m) end if !atmr !--- recv msg from atm --- call msg_atm_recv (Sa_a, Faia_a, Fala_a, Faoa_a) !--- cpl, atm, ice, lnd have advanced part of one day --- sec = sec + 86400/ncpl_a call control() ! reset stop, rest, hist control flags END DO !--- cpl & component models have advanced one day --- if (sec >= 86400) then eday = eday + 1 ! increment number of elapsed days sec = 0 end if call tcheck() ! verify time coordination call control() ! reset stop, rest, hist control flags !--- make a cpl restart file --- call restart ('write', Sa_a , Faia_a , Fala_a , Faoa_a , & Sl_l , Fall_l , Falo_l , & Si_i , Faii_i , Fioi_i , & So_o , Fioo_o ,aFoxx_o ) END DO WHILE 999 CONTINUE !--- send final msg to models & disconnect from msg-passing --- call msg_atm_final () call msg_ice_final () call msg_ocn_final () call msg_lnd_final () call msg_cpl_disconnect () STOP/END OF PROGRAM