FMS 2025.01.02-dev
Flexible Modeling System
Loading...
Searching...
No Matches
gex.F90
1!***********************************************************************
2!* GNU Lesser General Public License
3!*
4!* This file is part of the GFDL Flexible Modeling System (FMS).
5!*
6!* FMS is free software: you can redistribute it and/or modify it under
7!* the terms of the GNU Lesser General Public License as published by
8!* the Free Software Foundation, either version 3 of the License, or (at
9!* your option) any later version.
10!*
11!* FMS is distributed in the hope that it will be useful, but WITHOUT
12!* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13!* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14!* for more details.
15!*
16!* You should have received a copy of the GNU Lesser General Public
17!* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18!***********************************************************************
19
20!> @defgroup gex_mod gex_mod
21!> @ingroup gex
22!> @brief Simple generic exchange (gex) interface to pass (non-tracer) fields across components
23!> @author Fabien Paulot (Fabien.Paulot@noaa.gov)
24!!
25!!
26!!
27!!# 1. Introduction
28!!
29!!**gex** provides a generic interface to pass diagnostic fields across components.
30!!This interface is not meant to pass tracers across components.
31!!
32!!# 2. Setup
33!!
34!!## 2.1. Field table
35!!
36!!Each exchanged field needs to be specified in the `coupler_mod` field table as:
37!!
38!!> SENDING_COMPONENT_to_RECEIVING_COMPONENT_ex, "coupler_mod", GEX_NAME
39!!
40!!`SENDING_COMPONENT` and `RECEIVING_COMPONENT` can be `lnd`, `atm` and `ocn`
41!!`GEX_NAME` is the name under which the exchanged field is stored within **gex**
42!!
43!!Additional information can be provided regarding the field units.
44!!
45!!*Example*
46!!
47!! "atm_to_lnd_ex","coupler_mod","dryoa"
48!! "units","kg/m2/s"
49!! /
50!!
51!!
52!!
53!!## 2.2 Sending routine
54!!
55!!Two things need to happen:
56!!
57!!- At initialization, obtain index of exchanged field via:
58!!
59!! GEX_INDEX = gex_get_index(SENDING_COMPONENT,RECEIVING_COMPONENT,GEX_NAME)
60!!
61!! Returns `NO_TRACER` if `gex_name` is not found
62!!
63!! *Example*
64!!
65!! gex_dryoa = gex_get_index(MODEL_ATMOS,MODEL_LAND,'dryoa')
66!!
67!! requests index for `dryoa` field (exchanged from atmos->land) in gex.
68!!
69!!- Populate exchanged field
70!!
71!! gex_array(:,:,GEX_INDEX) = SOME_VALUE
72!!
73!! `gex array` is an array that contains all exchanged fields in the sending component.
74!! It needs to be made available in the routine where the field of interest is calculated.
75!!
76!! *Example*
77!!
78!! gex_atm2lnd(:,:,gex_dryoa) = pwt(:,:,kd)*dsinku_lnd(:,:,nomphilic)
79!!
80!! stores the total OA deposition
81!!
82!!## 2.3 Receiving routine
83!!
84!!Receiving is very similar to sending.
85!!
86!!- To get the index of requested field (at initialization)
87!!
88!! GEX_INDEX = gex_get_index(SENDING_COMPONENT,RECEIVING_COMPONENT,GEX_NAME)
89!!
90!!- To get value of exchanged field
91!!
92!! gex_array(:,:,GEX_INDEX)
93!!
94!! `gex array` is an array that contains all exchanged fields in the receiving component.
95!! It needs to be made available in the routine where the field of interest is needed
96!!
97!> @file
98!> @addtogroup gex_mod
99!> @brief File for @ref gex_mod
100
101module gex_mod
102
103use fms_mod, only: lowercase, error_mesg, fatal, note
104use tracer_manager_mod, only: no_tracer
105use field_manager_mod, only: model_land, model_atmos, model_ocean, num_models
106use field_manager_mod, only: fm_list_iter_type, fm_dump_list, fm_field_name_len, &
111use mpp_mod, only: mpp_root_pe, mpp_pe
112use fms_string_utils_mod, only: string
113
114implicit none ; private
115
116public :: gex_init, gex_get_index,gex_get_n_ex, gex_get_property, gex_name, gex_units
117public :: check_gex
118
119character(3) :: module_name = 'gex' !< module name
120logical :: initialized = .false. !< is module initialized
121
122integer, parameter :: gex_name = 1 !< internal index for gex_name
123integer, parameter :: gex_units = 2 !< internal index for gex unit
124
125!> @brief This type represents the entries for a specific exchanged field
126!> @ingroup gex_mod
128 character(fm_field_name_len):: name = '' !< gex name
129 character(fm_string_len) :: units = '' !< units (optional)
130 logical :: set = .false.
131end type gex_type
132
133!> @brief This type stores information about all the exchanged fields
134!> @ingroup gex_mod
136 type(gex_type), allocatable:: field(:)
137end type gex_type_r
138
139integer, allocatable :: n_gex(:,:)
140type(gex_type_r), allocatable :: gex_fields(:,:)
141
142!> @brief check that gex field was accessed by the sending component
143!> @ingroup gex_mod
144interface check_gex
145 module procedure check_gex_name
146 module procedure check_gex_index
147end interface check_gex
148
149
150!> @addtogroup gex_mod
151!> @{
152contains
153
154!> @brief Subroutine to initialize generic exchange between model components
155subroutine gex_init()
156 if (initialized) return
157
159
160 allocate(n_gex(num_models,num_models))
161 allocate(gex_fields(num_models,num_models))
162
163 n_gex(:,:) = 0
164
165 if (mpp_pe()==mpp_root_pe()) then
166 write(*,*) ''
167 write(*,*) '####################################'
168 write(*,*) '# generic exchanged fields [gex] #'
169 write(*,*) '####################################'
170 write(*,*) ''
171 end if
172
173 call gex_read_field_table('/coupler_mod/atm_to_lnd_ex',model_atmos,model_land)
174 call gex_read_field_table('/coupler_mod/lnd_to_atm_ex',model_land,model_atmos)
175 call gex_read_field_table('/coupler_mod/atm_to_ocn_ex',model_atmos,model_ocean)
176 call gex_read_field_table('/coupler_mod/ocn_to_atm_ex',model_ocean,model_atmos)
177
178 if (mpp_pe()==mpp_root_pe()) then
179 write(*,*) ''
180 write(*,*) '####################################'
181 write(*,*) ''
182 end if
183
184 initialized = .true.
185end subroutine gex_init
186
187!> @brief Subroutine to fields for a given exchange
188subroutine gex_read_field_table(listroot,MODEL_SRC,MODEL_REC)
189 character(len=*), intent(in) :: listroot !< name of the field manager list
190 integer, intent(in) :: MODEL_SRC !< index of the model where the field comes FROM
191 integer, intent(in) :: MODEL_REC !< index of the model where the field goes TO
192
193 type(fm_list_iter_type) :: iter ! iterator over the list of tracers
194 character(fm_field_name_len) :: name = '' ! name of the tracer
195 character(fm_type_name_len) :: ftype ! type of the field table entry (not used)
196 character(fm_path_name_len) :: listname ! name of the field manager list for each tracer
197
198 integer :: n
199
200 if(.not.fm_dump_list(listroot, recursive=.true.)) then
201 call error_mesg('gex_read_field_table', &
202 'Cannot dump field list "'//listroot//'". No additional field will be exchanged', &
203 note)
204 return
205 endif
206
207 n_gex(model_src,model_rec) = fm_get_length(listroot)
208 allocate(gex_fields(model_src,model_rec)%field(n_gex(model_src,model_rec)))
209
210 call fm_init_loop(listroot,iter)
211 do while (fm_loop_over_list(iter, name, ftype, n))
212 associate(fld=>gex_fields(model_src,model_rec)%field(n)) ! define a shorthand, to avoid very long expressions
213 fld%name = trim(name)
214 ! switch to the list of tracer parameters
215 listname = trim(listroot)//'/'//trim(name)
216 if (.not.fm_change_list(listname)) then
217 call error_mesg(module_name,'Cannot change fm list to "'//trim(listname)//'"', fatal)
218 endif
219 ! read parameters
220 fld%units = fm_util_get_string('units', caller = module_name, default_value = '', scalar = .true.)
221 ! other parameters can be read here, for example:
222
223 if (mpp_pe()==mpp_root_pe()) write(*,*) listroot,n, &
224 ' name="'//trim(fld%name)//'"', &
225 ' units="'//trim(fld%units)//'"'
226 end associate
227 end do
228end subroutine gex_read_field_table
229
230!> @brief Function to return number of fields exchanged
231function gex_get_n_ex(MODEL_SRC,MODEL_REC)
232 integer, intent(in) :: model_src !< index of the model where the field comes FROM
233 integer, intent(in) :: model_rec !< index of the model where the filed goes TO
234 integer :: gex_get_n_ex
235
236 if (.not. initialized) call error_mesg('flux_exchange|gex_get_n_ex','gex not initialized',fatal)
237
238 call gex_assert_valid_index(model_src, "MODEL_SRC", 1, num_models)
239 call gex_assert_valid_index(model_rec, "MODEL_REC", 1, num_models)
240
241 gex_get_n_ex = n_gex(model_src,model_rec)
242end function gex_get_n_ex
243
244!> @brief Function to return property value (string)
245function gex_get_property(MODEL_SRC,MODEL_REC,gex_index,property)
246 integer, intent(in) :: model_src !< index of the model where the field comes FROM
247 integer, intent(in) :: model_rec !< index of the model where the filed goes TO
248 integer, intent(in) :: gex_index !< gex index
249 integer, intent(in) :: property !< requested property
250 character(len=64) :: gex_get_property
251 integer :: n
252
253 if (.not. initialized) call error_mesg('flux_exchange|check_gex_property','gex not initialized',fatal)
254
255 n = gex_get_n_ex(model_src, model_rec)
256 call gex_assert_valid_index(gex_index, "tracer", 1, n)
257
258 associate(field => gex_fields(model_src,model_rec)%field(gex_index))
259 if (property.eq.gex_name) then
260 gex_get_property = trim(field%name)
261 elseif (property.eq.gex_units) then
262 gex_get_property = trim(field%units)
263 else
264 call error_mesg('flux_exchange|gex','property does not exist: ' // field%name,fatal)
265 end if
266 end associate
267end function gex_get_property
268
269!> @brief Function to return index of exchanged field
270function gex_get_index(MODEL_SRC,MODEL_REC,name,record)
271
272 character(len=*), intent(in) :: name !< name of the tracer
273 integer, intent(in) :: model_src !< index of the model where the field comes FROM
274 integer, intent(in) :: model_rec !< index of the model where the filed goes TO
275 logical, intent(in), optional :: record !< register that the field was accessed
276 integer :: i
277 integer :: gex_get_index
278
279 gex_get_index = no_tracer
280
281 if (.not. initialized) call error_mesg('flux_exchange|gex_get_index','gex not initialized',fatal)
282
283 do i = 1, n_gex(model_src,model_rec)
284 if (lowercase(trim(name)) == trim(gex_fields(model_src,model_rec)%field(i)%name)) then
285 gex_get_index = i
286 if (present(record)) then
287 if (record) gex_fields(model_src,model_rec)%field(i)%set = .true.
288 endif
289 exit
290 endif
291 enddo
292
293 return
294end function gex_get_index
295
296!> @brief Function to return the value of exchanged field and check that it was set
297function check_gex_name(MODEL_SRC,MODEL_REC,name)
298
299 integer, intent(in) :: model_src !< index of the model where the field comes FROM
300 integer, intent(in) :: model_rec !< index of the model where the filed goes TO
301 character(len=*), intent(in) :: name !< name of the tracer
302
303 logical :: check_gex_name
304
305 integer :: index
306
307 if (.not. initialized) call error_mesg('flux_exchange|check_gex_name','gex not initialized',fatal)
308
309 index = gex_get_index(model_src,model_rec,name)
310 check_gex_name = .false.
311 if (index.eq.no_tracer) then
312 call error_mesg('flux_exchange|gex','requested gex field does not exist '// &
313 name,fatal)
314 else
315 if (gex_fields(model_src,model_rec)%field(index)%set) then
316 check_gex_name = .true.
317 else
318 call error_mesg('flux_exchange|gex','requested gex field not set '// &
319 name,fatal)
320 end if
321 end if
322
323 end function check_gex_name
324
325!> @brief Function to check if gex index is properly set
326function check_gex_index(MODEL_SRC,MODEL_REC,index)
327
328 integer, intent(in) :: model_src !< index of the model where the field comes FROM
329 integer, intent(in) :: model_rec !< index of the model where the filed goes TO
330 integer, intent(in) :: index !< gex index
331 logical :: check_gex_index
332
333 check_gex_index = .false.
334
335 if (index.eq.no_tracer) then
336 call error_mesg('flux_exchange|gex','requested gex field does not exist '// &
337 gex_fields(model_src,model_rec)%field(index)%name,fatal)
338 else
339 if (gex_fields(model_src,model_rec)%field(index)%set) then
340 check_gex_index = .true.
341 else
342 call error_mesg('flux_exchange|gex','requested gex field not set '// &
343 gex_fields(model_src,model_rec)%field(index)%name,fatal)
344 end if
345 end if
346 end function check_gex_index
347
348
349!> @brief Check that an index falls within a range of valid values
350subroutine gex_assert_valid_index(indx, name, lb, ub)
351 integer, intent(in) :: indx !< Index to check
352 integer, intent(in) :: lb !< Lower bound of valid indices
353 integer, intent(in) :: ub !< Upper bound of valid indices
354 character(*), intent(in) :: name !< Name of the index
355
356 if (indx.lt.lb .or. indx.gt.ub) then
357 call error_mesg(module_name, "Invalid " // name // " index: " // string(indx), fatal)
358 endif
359end subroutine gex_assert_valid_index
360
361end module gex_mod
362
363
364!> @}
365! close documentation grouping
character(len=fms_path_len) function, public fm_get_current_list()
A function to return the full path of the current list.
integer, parameter, public fm_string_len
The length of a character string representing character values for the field.
logical function, public fm_dump_list(name, recursive, unit)
A function to list properties associated with a field.
integer, parameter, public model_land
Land model.
subroutine, public fm_init_loop(loop_list, iter)
given a name of the list, prepares an iterator over the list content. If the name of the given list i...
logical function, public fm_change_list(name)
Change the current list. Return true on success, false otherwise.
integer, parameter, public fm_field_name_len
The length of a character string representing the field name.
integer, parameter, public fm_type_name_len
The length of a character string representing the various types that the values of the field can take...
integer, parameter, public model_ocean
Ocean model.
integer, parameter, public fm_path_name_len
The length of a character string representing the field path.
integer, parameter, public model_atmos
Atmospheric model.
integer, parameter, public num_models
Number of models (ATMOS, OCEAN, LAND, ICE, COUPLER).
subroutine, public field_manager_init(nfields, table_name)
Routine to initialize the field manager.
integer function, public fm_get_length(name)
A function to return how many elements are contained within the named list or entry.
A function for looping over a list.
Iterator over the field manager list.
character(len=fm_string_len) function, public fm_util_get_string(name, caller, index, default_value, scalar)
Get a string value from the Field Manager tree.
Definition fm_util.F90:1462
real(r8_kind) function, public fm_util_get_real(name, caller, index, default_value, scalar)
Get a real value from the Field Manager tree.
Definition fm_util.F90:1341
logical function, public fm_util_get_logical(name, caller, index, default_value, scalar)
Get a logical value from the Field Manager tree.
Definition fm_util.F90:1227
character(:) function, allocatable, public string(v, fmt)
Converts a number or a Boolean value to a string.
integer function, public gex_get_n_ex(model_src, model_rec)
Function to return number of fields exchanged.
Definition gex.F90:232
subroutine gex_assert_valid_index(indx, name, lb, ub)
Check that an index falls within a range of valid values.
Definition gex.F90:351
subroutine, public gex_init()
Subroutine to initialize generic exchange between model components.
Definition gex.F90:156
subroutine gex_read_field_table(listroot, model_src, model_rec)
Subroutine to fields for a given exchange.
Definition gex.F90:189
integer function, public gex_get_index(model_src, model_rec, name, record)
Function to return index of exchanged field.
Definition gex.F90:271
logical function check_gex_index(model_src, model_rec, index)
Function to check if gex index is properly set.
Definition gex.F90:327
logical function check_gex_name(model_src, model_rec, name)
Function to return the value of exchanged field and check that it was set.
Definition gex.F90:298
character(len=64) function, public gex_get_property(model_src, model_rec, gex_index, property)
Function to return property value (string)
Definition gex.F90:246
check that gex field was accessed by the sending component
Definition gex.F90:144
This type represents the entries for a specific exchanged field.
Definition gex.F90:127
This type stores information about all the exchanged fields.
Definition gex.F90:135