FMS 2025.01-dev
Flexible Modeling System
Loading...
Searching...
No Matches
coupler_types.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!> @defgroup coupler_types_mod coupler_types_mod
20!> @ingroup coupler
21!> @brief This module contains type declarations for the coupler.
22!> @author Richard Slater, John Dunne
23
24!> @addtogroup coupler_types_mod
25!> @{
26module coupler_types_mod
27 use fms_mod, only: write_version_number, lowercase
28 use fms2_io_mod, only: fmsnetcdfdomainfile_t, open_file, register_restart_field
29 use fms2_io_mod, only: register_axis, unlimited, variable_exists, check_if_open
30 use fms2_io_mod, only: register_field, get_num_dimensions, variable_att_exists
31 use fms2_io_mod, only: get_variable_attribute, get_dimension_size, get_dimension_names
32 use fms2_io_mod, only: register_variable_attribute, get_variable_dimension_names
33 use fms2_io_mod, only: get_variable_num_dimensions
34#ifdef use_deprecated_io
35 use fms_io_mod, only: restart_file_type, fms_io_register_restart_field=>register_restart_field
36 use fms_io_mod, only: query_initialized, restore_state
37#endif
38 use time_manager_mod, only: time_type
39 use diag_manager_mod, only: register_diag_field, send_data
40 use data_override_mod, only: data_override
41 use mpp_domains_mod, only: domain2d, mpp_redistribute
42 use mpp_mod, only: mpp_error, fatal, mpp_chksum
43 use fms_string_utils_mod, only: string
44 use platform_mod, only: r4_kind, r8_kind, i8_kind, fms_file_len, fms_path_len
45
46 implicit none
47 private
48
49
50 ! Include variable "version" to be written to log file.
51#include<file_version.h>
52
61
64
65 character(len=*), parameter :: mod_name = 'coupler_types_mod'
66
67!> @}
68
69 !! mixed precision methodology for the encapsulated types:
70 !!
71 !! bc(:) (coupler_nd_real8_field) -> field(:) (coupler_nd_real8_values)
72 !! coupler_nd_bc_type <
73 !! bc_r4(:) (coupler_nd_real4_field) -> field(:) (coupler_nd_real4_values)
74 !!
75 !! Arrays (values + field) are typically directly allocated and then 'spawn' can be used to create a new type
76 !! from a previously allocated 'template' type
77
78 !> Coupler data for 3D values
79 !> @ingroup coupler_types_mod
81 character(len=48) :: name = ' ' !< The diagnostic name for this array
82 logical :: mean = .true. !< mean
83 logical :: override = .false. !< override
84 integer :: id_diag = 0 !< The diagnostic id for this array
85 character(len=128) :: long_name = ' ' !< The diagnostic long_name for this array
86 character(len=128) :: units = ' ' !< The units for this array
87 integer :: id_rest = 0 !< The id of this array in the restart field
88 logical :: may_init = .true. !< If true, there is an internal method
89 !! that can be used to initialize this field
90 !! if it can not be read from a restart file
91 real(r8_kind), pointer, contiguous, dimension(:,:,:) :: values => null() !< The pointer to the
92 !! array of values for this field; this
93 !! should be changed to allocatable
95
96 !> Coupler data for 3D fields
97 !> @ingroup coupler_types_mod
99 character(len=48) :: name = ' ' !< name
100 integer :: num_fields = 0 !< num_fields
101 type(coupler_3d_real8_values_type), pointer, dimension(:) :: field => null() !< field
102 character(len=128) :: flux_type = ' ' !< flux_type
103 character(len=128) :: implementation = ' ' !< implementation
104 logical, pointer, dimension(:) :: flag => null() !< flag
105 integer :: atm_tr_index = 0 !< atm_tr_index
106 character(len=FMS_FILE_LEN) :: ice_restart_file = ' ' !< ice_restart_file
107 character(len=FMS_FILE_LEN) :: ocean_restart_file = ' ' !< ocean_restart_file
108#ifdef use_deprecated_io
109 type(restart_file_type), pointer :: rest_type => null() !< A pointer to the restart_file_type
110 !! that is used for this field.
111#endif
112 type(fmsnetcdfdomainfile_t), pointer :: fms2_io_rest_type => null() !< A pointer to the restart_file_type
113 !! That is used for this field
114 logical :: use_atm_pressure !< use_atm_pressure
115 logical :: use_10m_wind_speed !< use_10m_wind_speed
116 logical :: pass_through_ice !< pass_through_ice
117 real(r8_kind), pointer, dimension(:) :: param => null() !< param
118 real(r8_kind) :: mol_wt = 0.0_r8_kind !< mol_wt
120
121 !> Coupler data for 3D values
122 !> @ingroup coupler_types_mod
124 character(len=48) :: name = ' ' !< The diagnostic name for this array
125 logical :: mean = .true. !< mean
126 logical :: override = .false. !< override
127 integer :: id_diag = 0 !< The diagnostic id for this array
128 character(len=128) :: long_name = ' ' !< The diagnostic long_name for this array
129 character(len=128) :: units = ' ' !< The units for this array
130 integer :: id_rest = 0 !< The id of this array in the restart field
131 logical :: may_init = .true. !< If true, there is an internal method
132 !! that can be used to initialize this field
133 !! if it can not be read from a restart file
134 real(r4_kind), pointer, contiguous, dimension(:,:,:) :: values => null() !< The pointer to the
135 !! array of values for this field; this
136 !! should be changed to allocatable
138
139 !> Coupler data for 3D fields
140 !> @ingroup coupler_types_mod
142 character(len=48) :: name = ' ' !< name
143 integer :: num_fields = 0 !< num_fields
144 type(coupler_3d_real4_values_type), pointer, dimension(:) :: field => null() !< field
145 character(len=128) :: flux_type = ' ' !< flux_type
146 character(len=128) :: implementation = ' ' !< implementation
147 logical, pointer, dimension(:) :: flag => null() !< flag
148 integer :: atm_tr_index = 0 !< atm_tr_index
149 character(len=FMS_FILE_LEN) :: ice_restart_file = ' ' !< ice_restart_file
150 character(len=FMS_FILE_LEN) :: ocean_restart_file = ' ' !< ocean_restart_file
151#ifdef use_deprecated_io
152 type(restart_file_type), pointer :: rest_type => null() !< A pointer to the restart_file_type
153 !! that is used for this field.
154#endif
155 type(fmsnetcdfdomainfile_t), pointer :: fms2_io_rest_type => null() !< A pointer to the restart_file_type
156 !! That is used for this field
157 logical :: use_atm_pressure !< use_atm_pressure
158 logical :: use_10m_wind_speed !< use_10m_wind_speed
159 logical :: pass_through_ice !< pass_through_ice
160 !> precision needs to be r8_kind since this array is retrieved from the field_manager routine
161 !! fm_util_get_real_array which only returns a r8_kind
162 !! Might be able to change to allocatable(?) to do a conversion
163 real(r8_kind), pointer, dimension(:) :: param => null() !< param
164 real(r8_kind) :: mol_wt = 0.0_r8_kind !< mol_wt
166
167 !> Coupler data for 3D boundary conditions
168 !> @ingroup coupler_types_mod
169 type, public :: coupler_3d_bc_type
170 integer :: num_bcs = 0 !< The number of boundary condition fields
171 type(coupler_3d_real8_field_type), dimension(:), pointer :: bc => null() !< A pointer to the array of boundary
172 !! TODO above should be renamed eventually to indicate kind=8
173 type(coupler_3d_real4_field_type), dimension(:), pointer :: bc_r4 => null() !< A pointer to the array of boundary
174 logical :: set = .false. !< If true, this type has been initialized
175 integer :: isd, isc, iec, ied !< The i-direction data and computational domain index ranges for this type
176 integer :: jsd, jsc, jec, jed !< The j-direction data and computational domain index ranges for this type
177 integer :: ks, ke !< The k-direction index ranges for this type
178 end type coupler_3d_bc_type
179
180
181 !> Coupler data for 2D values
182 !> @ingroup coupler_types_mod
184 character(len=48) :: name = ' ' !< The diagnostic name for this array
185 real(r8_kind), pointer, contiguous, dimension(:,:) :: values => null() !< The pointer to the
186 !! array of values for this field; this
187 !! should be changed to allocatable
188 logical :: mean = .true. !< mean
189 logical :: override = .false. !< override
190 integer :: id_diag = 0 !< The diagnostic id for this array
191 character(len=128) :: long_name = ' ' !< The diagnostic long_name for this array
192 character(len=128) :: units = ' ' !< The units for this array
193 integer :: id_rest = 0 !< The id of this array in the restart field
194 logical :: may_init = .true. !< If true, there is an internal method
195 !! that can be used to initialize this field
196 !! if it can not be read from a restart file
198
199 !> Coupler data for 2D fields
200 !> @ingroup coupler_types_mod
202 character(len=48) :: name = ' ' !< name
203 integer :: num_fields = 0 !< num_fields
204 type(coupler_2d_real8_values_type), pointer, dimension(:) :: field => null() !< field
205 character(len=128) :: flux_type = ' ' !< flux_type
206 character(len=128) :: implementation = ' ' !< implementation
207 real(r8_kind), pointer, dimension(:) :: param => null() !< param
208 logical, pointer, dimension(:) :: flag => null() !< flag
209 integer :: atm_tr_index = 0 !< atm_tr_index
210 character(len=FMS_FILE_LEN) :: ice_restart_file = ' ' !< ice_restart_file
211 character(len=FMS_FILE_LEN) :: ocean_restart_file = ' ' !< ocean_restart_file
212#ifdef use_deprecated_io
213 type(restart_file_type), pointer :: rest_type => null() !< A pointer to the restart_file_type
214 !! that is used for this field.
215#endif
216 type(fmsnetcdfdomainfile_t), pointer :: fms2_io_rest_type => null() !< A pointer to the restart_file_type
217 !! That is used for this field
218 logical :: use_atm_pressure !< use_atm_pressure
219 logical :: use_10m_wind_speed !< use_10m_wind_speed
220 logical :: pass_through_ice !< pass_through_ice
221 real(r8_kind) :: mol_wt = 0.0_r8_kind !< mol_wt
223
224 !> Coupler data for 2D values
225 !> @ingroup coupler_types_mod
227 character(len=44) :: name = ' ' !< The diagnostic name for this array
228 real(r4_kind), pointer, contiguous, dimension(:,:) :: values => null() !< The pointer to the
229 !! array of values for this field; this
230 !! should be changed to allocatable
231 logical :: mean = .true. !< mean
232 logical :: override = .false. !< override
233 integer :: id_diag = 0 !< The diagnostic id for this array
234 character(len=124) :: long_name = ' ' !< The diagnostic long_name for this array
235 character(len=124) :: units = ' ' !< The units for this array
236 integer :: id_rest = 0 !< The id of this array in the restart field
237 logical :: may_init = .true. !< If true, there is an internal method
238 !! that can be used to initialize this field
239 !! if it can not be read from a restart file
241
242 !> Coupler data for 2D fields
243 !> @ingroup coupler_types_mod
245 character(len=44) :: name = ' ' !< name
246 integer :: num_fields = 0 !< num_fields
247 type(coupler_2d_real4_values_type), pointer, dimension(:) :: field => null() !< field
248 character(len=124) :: flux_type = ' ' !< flux_type
249 character(len=124) :: implementation = ' ' !< implementation
250 !> precision needs to be r8_kind since this array is retrieved from the field_manager routine
251 !! fm_util_get_real_array which only returns a r8_kind
252 !! Might be able to change to allocatable(?) to do a conversion
253 real(r8_kind), pointer, dimension(:) :: param => null() !< param
254 logical, pointer, dimension(:) :: flag => null() !< flag
255 integer :: atm_tr_index = 0 !< atm_tr_index
256 character(len=FMS_FILE_LEN) :: ice_restart_file = ' ' !< ice_restart_file
257 character(len=FMS_FILE_LEN) :: ocean_restart_file = ' ' !< ocean_restart_file
258#ifdef use_deprecated_io
259 type(restart_file_type), pointer :: rest_type => null() !< A pointer to the restart_file_type
260 !! that is used for this field.
261#endif
262 type(fmsnetcdfdomainfile_t), pointer :: fms2_io_rest_type => null() !< A pointer to the restart_file_type
263 !! That is used for this field
264 logical :: use_atm_pressure !< use_atm_pressure
265 logical :: use_10m_wind_speed !< use_10m_wind_speed
266 logical :: pass_through_ice !< pass_through_ice
267 real(r8_kind) :: mol_wt = 0.0_r8_kind !< mol_wt
269
270 !> Coupler data for 2D boundary conditions
271 !> @ingroup coupler_types_mod
272 type, public :: coupler_2d_bc_type
273 integer :: num_bcs = 0 !< The number of boundary condition fields
274 type(coupler_2d_real8_field_type), dimension(:), pointer :: bc => null() !< A pointer to the array of boundary
275 !! condition fields
276 type(coupler_2d_real4_field_type), dimension(:), pointer :: bc_r4 => null() !< A pointer to the array of boundary
277 !! condition fields
278 logical :: set = .false. !< If true, this type has been initialized
279 integer :: isd, isc, iec, ied !< The i-direction data and computational domain index ranges for this type
280 integer :: jsd, jsc, jec, jed !< The j-direction data and computational domain index ranges for this type
281 end type coupler_2d_bc_type
282
283 !> Coupler data for 1D values
284 !> @ingroup coupler_types_mod
286 character(len=48) :: name = ' ' !< The diagnostic name for this array
287 real(r8_kind), pointer, dimension(:) :: values => null() !< The pointer to the array of values
288 logical :: mean = .true. !< mean
289 logical :: override = .false. !< override
290 integer :: id_diag = 0 !< The diagnostic id for this array
291 character(len=128) :: long_name = ' ' !< The diagnostic long_name for this array
292 character(len=128) :: units = ' ' !< The units for this array
293 logical :: may_init = .true. !< If true, there is an internal method
294 !! that can be used to initialize this field
295 !! if it can not be read from a restart file
297
298 !> Coupler data for 1D fields
299 !> @ingroup coupler_types_mod
301 character(len=48) :: name = ' ' !< name
302 integer :: num_fields = 0 !< num_fields
303 type(coupler_1d_real8_values_type), pointer, dimension(:) :: field => null() !< field
304 character(len=128) :: flux_type = ' ' !< flux_type
305 character(len=128) :: implementation = ' ' !< implementation
306 !> precision has been explicitly defined
307 !! to be r8_kind during mixedmode update to field_manager
308 !! this explicit definition can be removed during the coupler update and be made into FMS_CP_KIND_
309 real(r8_kind), pointer, dimension(:) :: param => null() !< param
310 logical, pointer, dimension(:) :: flag => null() !< flag
311 integer :: atm_tr_index = 0 !< atm_tr_index
312 character(len=FMS_FILE_LEN) :: ice_restart_file = ' ' !< ice_restart_file
313 character(len=FMS_FILE_LEN) :: ocean_restart_file = ' ' !< ocean_restart_file
314 logical :: use_atm_pressure !< use_atm_pressure
315 logical :: use_10m_wind_speed !< use_10m_wind_speed
316 logical :: pass_through_ice !< pass_through_ice
317 !> precision has been explicitly defined
318 !! to be r8_kind during mixedmode update to field_manager
319 !! this explicit definition can be removed during the coupler update and be made into FMS_CP_KIND_
320 real(r8_kind) :: mol_wt = 0.0_r8_kind !< mol_wt
321
323
324 !> Coupler data for 1D values
325 !> @ingroup coupler_types_mod
327 character(len=48) :: name = ' ' !< The diagnostic name for this array
328 real(r4_kind), pointer, dimension(:) :: values => null() !< The pointer to the array of values
329 logical :: mean = .true. !< mean
330 logical :: override = .false. !< override
331 integer :: id_diag = 0 !< The diagnostic id for this array
332 character(len=128) :: long_name = ' ' !< The diagnostic long_name for this array
333 character(len=128) :: units = ' ' !< The units for this array
334 logical :: may_init = .true. !< If true, there is an internal method
335 !! that can be used to initialize this field
336 !! if it can not be read from a restart file
338
339 !> Coupler data for 1D fields
340 !> @ingroup coupler_types_mod
342 character(len=48) :: name = ' ' !< name
343 integer :: num_fields = 0 !< num_fields
344 type(coupler_1d_real4_values_type), pointer, dimension(:) :: field => null() !< field
345 character(len=128) :: flux_type = ' ' !< flux_type
346 character(len=128) :: implementation = ' ' !< implementation
347 !> precision needs to be r8_kind since this array is retrieved from the field_manager routine
348 !! fm_util_get_real_array which only returns a r8_kind
349 !! Might be able to change to allocatable(?) to do a conversion
350 real(r8_kind), pointer, dimension(:) :: param => null() !< param
351 logical, pointer, dimension(:) :: flag => null() !< flag
352 integer :: atm_tr_index = 0 !< atm_tr_index
353 character(len=FMS_FILE_LEN) :: ice_restart_file = ' ' !< ice_restart_file
354 character(len=FMS_FILE_LEN) :: ocean_restart_file = ' ' !< ocean_restart_file
355 logical :: use_atm_pressure !< use_atm_pressure
356 logical :: use_10m_wind_speed !< use_10m_wind_speed
357 logical :: pass_through_ice !< pass_through_ice
358 !> This is also read in r8 from the field manager, but since its not a pointer the conversion is allowed
359 real(r8_kind) :: mol_wt = 0.0_r8_kind !< mol_wt
360
362
363 !> Coupler data for 1D boundary conditions
364 !> @ingroup coupler_types_mod
365 type, public :: coupler_1d_bc_type
366 integer :: num_bcs = 0 !< The number of boundary condition fields
367 type(coupler_1d_real8_field_type), dimension(:), pointer :: bc => null() !< A pointer to the array of boundary
368 !! condition fields
369 type(coupler_1d_real4_field_type), dimension(:), pointer :: bc_r4 => null() !< A pointer to the array of boundary
370 !! condition fields
371 logical :: set = .false. !< If true, this type has been initialized
372 end type coupler_1d_bc_type
373
374 !> @addtogroup coupler_types_mod
375 !> @{
376 ! The following public parameters can help in selecting the sub-elements of a
377 ! coupler type. There are duplicate values because different boundary
378 ! conditions have different sub-elements.
379 ! Note: These should be parameters, but doing so would break openMP directives.
380 integer, public :: ind_pcair = 1 !< The index of the atmospheric concentration
381 integer, public :: ind_u10 = 2 !< The index of the 10 m wind speed
382 integer, public :: ind_psurf = 3 !< The index of the surface atmospheric pressure
383 integer, public :: ind_alpha = 1 !< The index of the solubility array for a tracer
384 integer, public :: ind_csurf = 2 !< The index of the ocean surface concentration
385 integer, public :: ind_sc_no = 3 !< The index for the Schmidt number for a tracer flux
386 integer, public :: ind_flux = 1 !< The index for the tracer flux
387 integer, public :: ind_deltap= 2 !< The index for ocean-air gas partial pressure change
388 integer, public :: ind_kw = 3 !< The index for the piston velocity
389 integer, public :: ind_flux0 = 4 !< The index for the piston velocity
390 integer, public :: ind_deposition = 1 !< The index for the atmospheric deposition flux
391 integer, public :: ind_runoff = 1 !< The index for a runoff flux
392 !> @}
393
394 ! Interface definitions for overloaded routines
395
396 !> This is the interface to spawn one coupler_bc_type into another and then
397 !! register diagnostics associated with the new type.
398 !> @ingroup coupler_types_mod
403 end interface coupler_type_copy
404
405 !> This is the interface to spawn one coupler_bc_type into another.
406 !> @ingroup coupler_types_mod
410 end interface coupler_type_spawn
411
412 !> This is the interface to copy the field data from one coupler_bc_type
413 !! to another of the same rank, size and decomposition.
414 !> @ingroup coupler_types_mod
417 end interface coupler_type_copy_data
418
419 !> This is the interface to redistribute the field data from one coupler_bc_type
420 !! to another of the same rank and global size, but a different decomposition.
421 !> @ingroup coupler_types_mod
425
426 !> This is the interface to rescale the field data in a coupler_bc_type.
427 !> @ingroup coupler_types_mod
429 module procedure ct_rescale_data_2d_r4, ct_rescale_data_3d_r4
430 module procedure ct_rescale_data_2d_r8, ct_rescale_data_3d_r8
431 end interface coupler_type_rescale_data
432
433 !> This is the interface to increment the field data from one coupler_bc_type
434 !! with the data from another. Both must have the same horizontal size and
435 !! decomposition, but a 2d type may be incremented by a 2d or 3d type
436 !> @ingroup coupler_types_mod
439 module procedure ct_increment_data_2d_3d_r4, ct_increment_data_2d_3d_r8
440 end interface coupler_type_increment_data
441
442 !> This is the interface to extract a field in a coupler_bc_type into an array.
443 !> @ingroup coupler_types_mod
445 module procedure ct_extract_data_2d_r4, ct_extract_data_2d_r8
446 module procedure ct_extract_data_3d_r4, ct_extract_data_3d_r8
447 module procedure ct_extract_data_3d_2d_r4, ct_extract_data_3d_2d_r8
448 end interface coupler_type_extract_data
449
450 !> This is the interface to set a field in a coupler_bc_type from an array.
451 !> @ingroup coupler_types_mod
453 module procedure ct_set_data_2d_r4, ct_set_data_3d_r4, ct_set_data_2d_3d_r4
454 module procedure ct_set_data_2d_r8, ct_set_data_3d_r8, ct_set_data_2d_3d_r8
455 end interface coupler_type_set_data
456
457 !> This is the interface to set diagnostics for the arrays in a coupler_bc_type.
458 !> @ingroup coupler_types_mod
461 end interface coupler_type_set_diags
462
463 !> This is the interface to write out checksums for the elements of a coupler_bc_type.
464 !> @ingroup coupler_types_mod
467 end interface coupler_type_write_chksums
468
469 !> This is the interface to write out diagnostics of the arrays in a coupler_bc_type.
470 !> @ingroup coupler_types_mod
473 end interface coupler_type_send_data
474
475 !> This is the interface to override the values of the arrays in a coupler_bc_type.
476 !> @ingroup coupler_types_mod
479 end interface coupler_type_data_override
480
481 !> This is the interface to register the fields in a coupler_bc_type to be saved
482 !! in restart files.
483 !> @ingroup coupler_types_mod
485#ifdef use_deprecated_io
486 module procedure mpp_io_ct_register_restarts_2d, mpp_io_ct_register_restarts_3d
487 module procedure mpp_io_ct_register_restarts_to_file_2d, mpp_io_ct_register_restarts_to_file_3d
488#endif
491
492 !> This is the interface to read in the fields in a coupler_bc_type that have
493 !! been saved in restart files.
494 !> @ingroup coupler_types_mod
496#ifdef use_deprecated_io
497 module procedure mpp_io_ct_restore_state_2d, mpp_io_ct_restore_state_3d
498#endif
500 end interface coupler_type_restore_state
501
502 !> This function interface indicates whether a coupler_bc_type has been initialized.
503 !> @ingroup coupler_types_mod
506 end interface coupler_type_initialized
507
508 !> This is the interface to deallocate any data associated with a coupler_bc_type.
509 !> @ingroup coupler_types_mod
512 end interface coupler_type_destructor
513
514contains
515
516!> @addtogroup coupler_types_mod
517!> @{
518
519 !> @brief Initialize the coupler types
521
522 logical, save :: module_is_initialized = .false.
523
524 ! Return if already intialized
525 if (module_is_initialized) then
526 return
527 endif
528
529 ! Write out the version of the file to the log file.
530 call write_version_number(trim(mod_name), version)
531
532 module_is_initialized = .true.
533
534 return
535 end subroutine coupler_types_init !}
536
537
538 !> @brief Copy fields from one coupler type to another. 1-D to 2-D version for generic coupler_type_copy.
539 !!
540 !! @throw FATAL, "Number of output fields exceeds zero"
541 subroutine coupler_type_copy_1d_2d(var_in, var_out, is, ie, js, je,&
542 & diag_name, axes, time, suffix)
543 type(coupler_1d_bc_type), intent(in) :: var_in !< variable to copy information from
544 type(coupler_2d_bc_type), intent(inout) :: var_out !< variable to copy information to
545 integer, intent(in) :: is !< lower bound of first dimension
546 integer, intent(in) :: ie !< upper bound of first dimension
547 integer, intent(in) :: js !< lower bound of second dimension
548 integer, intent(in) :: je !< upper bound of second dimension
549 character(len=*), intent(in) :: diag_name !< name for diagnostic file--if blank, then
550 !! don't register the fields
551 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
552 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
553 character(len=*), intent(in), optional :: suffix !< optional suffix to make the name identifier unique
554
555 character(len=*), parameter :: error_header =&
556 & '==>Error from coupler_types_mod (coupler_type_copy_1d_2d):'
557
558 if (var_out%num_bcs > 0) then
559 ! It is an error if the number of output fields exceeds zero, because it means this
560 ! type has already been populated.
561 call mpp_error(fatal, trim(error_header) // ' Number of output fields exceeds zero')
562 endif
563
564 if (var_in%num_bcs >= 0)&
565 & call ct_spawn_1d_2d(var_in, var_out, (/ is, is, ie, ie /), (/ js, js, je, je /), suffix)
566
567 if ((var_out%num_bcs > 0) .and. (diag_name .ne. ' '))&
568 & call ct_set_diags_2d(var_out, diag_name, axes, time)
569 end subroutine coupler_type_copy_1d_2d
570
571 !> @brief Copy fields from one coupler type to another. 1-D to 3-D version for generic coupler_type_copy.
572 !!
573 !!
574 !! @throw FATAL, "Number of output fields is exceeds zero"
575 subroutine coupler_type_copy_1d_3d(var_in, var_out, is, ie, js, je, kd,&
576 & diag_name, axes, time, suffix)
577 type(coupler_1d_bc_type), intent(in) :: var_in !< variable to copy information from
578 type(coupler_3d_bc_type), intent(inout) :: var_out !< variable to copy information to
579 integer, intent(in) :: is !< lower bound of first dimension
580 integer, intent(in) :: ie !< upper bound of first dimension
581 integer, intent(in) :: js !< lower bound of second dimension
582 integer, intent(in) :: je !< upper bound of second dimension
583 integer, intent(in) :: kd !< third dimension
584 character(len=*), intent(in) :: diag_name !< name for diagnostic file--if blank, then
585 !! don't register the fields
586 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
587 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
588 character(len=*), intent(in), optional :: suffix !< optional suffix to make the name identifier unique
589
590 character(len=*), parameter :: error_header =&
591 & '==>Error from coupler_types_mod (coupler_type_copy_1d_3d):'
592
593 if (var_out%num_bcs > 0) then
594 ! It is an error if the number of output fields exceeds zero, because it means this
595 ! type has already been populated.
596 call mpp_error(fatal, trim(error_header) // ' Number of output fields exceeds zero')
597 endif
598
599 if (var_in%num_bcs >= 0)&
600 & call ct_spawn_1d_3d(var_in, var_out, (/ is, is, ie, ie /), (/ js, js, je, je /), (/1, kd/), suffix)
601
602 if ((var_out%num_bcs > 0) .and. (diag_name .ne. ' '))&
603 & call ct_set_diags_3d(var_out, diag_name, axes, time)
604 end subroutine coupler_type_copy_1d_3d
605
606 !> @brief Copy fields from one coupler type to another. 2-D to 2-D version for generic coupler_type_copy.
607 !!
608 !! @throw FATAL, "Number of output fields is exceeds zero"
609 subroutine coupler_type_copy_2d_2d(var_in, var_out, is, ie, js, je,&
610 & diag_name, axes, time, suffix)
611 type(coupler_2d_bc_type), intent(in) :: var_in !< variable to copy information from
612 type(coupler_2d_bc_type), intent(inout) :: var_out !< variable to copy information to
613 integer, intent(in) :: is !< lower bound of first dimension
614 integer, intent(in) :: ie !< upper bound of first dimension
615 integer, intent(in) :: js !< lower bound of second dimension
616 integer, intent(in) :: je !< upper bound of second dimension
617 character(len=*), intent(in) :: diag_name !< name for diagnostic file--if blank, then
618 !! don't register the fields
619 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
620 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
621 character(len=*), intent(in), optional :: suffix !< optional suffix to make the name identifier unique
622
623 character(len=*), parameter :: error_header =&
624 & '==>Error from coupler_types_mod (coupler_type_copy_2d_2d):'
625
626 if (var_out%num_bcs > 0) then
627 ! It is an error if the number of output fields exceeds zero, because it means this
628 ! type has already been populated.
629 call mpp_error(fatal, trim(error_header) // ' Number of output fields exceeds zero')
630 endif
631
632 if (var_in%num_bcs >= 0)&
633 & call ct_spawn_2d_2d(var_in, var_out, (/ is, is, ie, ie /), (/ js, js, je, je /), suffix)
634
635 if ((var_out%num_bcs > 0) .and. (diag_name .ne. ' '))&
636 & call ct_set_diags_2d(var_out, diag_name, axes, time)
637 end subroutine coupler_type_copy_2d_2d
638
639 !> @brief Copy fields from one coupler type to another. 2-D to 3-D version for generic coupler_type_copy.
640 !!
641 !! @throw FATAL, "Number of output fields is exceeds zero"
642 subroutine coupler_type_copy_2d_3d(var_in, var_out, is, ie, js, je, kd,&
643 & diag_name, axes, time, suffix)
644 type(coupler_2d_bc_type), intent(in) :: var_in !< variable to copy information from
645 type(coupler_3d_bc_type), intent(inout) :: var_out !< variable to copy information to
646 integer, intent(in) :: is !< lower bound of first dimension
647 integer, intent(in) :: ie !< upper bound of first dimension
648 integer, intent(in) :: js !< lower bound of second dimension
649 integer, intent(in) :: je !< upper bound of second dimension
650 integer, intent(in) :: kd !< third dimension
651 character(len=*), intent(in) :: diag_name !< name for diagnostic file--if blank, then
652 !! don't register the fields
653 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
654 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
655 character(len=*), intent(in), optional :: suffix !< optional suffix to make the name identifier unique
656
657 character(len=*), parameter :: error_header =&
658 & '==>Error from coupler_types_mod (coupler_type_copy_2d_3d):'
659
660 if (var_out%num_bcs > 0) then
661 ! It is an error if the number of output fields exceeds zero, because it means this
662 ! type has already been populated.
663 call mpp_error(fatal, trim(error_header) // ' Number of output fields exceeds zero')
664 endif
665
666 if (var_in%num_bcs >= 0)&
667 & call ct_spawn_2d_3d(var_in, var_out, (/ is, is, ie, ie /), (/ js, js, je, je /), (/1, kd/), suffix)
668
669 if ((var_out%num_bcs > 0) .and. (diag_name .ne. ' '))&
670 & call ct_set_diags_3d(var_out, diag_name, axes, time)
671 end subroutine coupler_type_copy_2d_3d
672
673 !> @brief Copy fields from one coupler type to another. 3-D to 2-D version for generic coupler_type_copy.
674 !!
675 !! @throw FATAL, "Number of output fields is exceeds zero"
676 subroutine coupler_type_copy_3d_2d(var_in, var_out, is, ie, js, je,&
677 & diag_name, axes, time, suffix)
678 type(coupler_3d_bc_type), intent(in) :: var_in !< variable to copy information from
679 type(coupler_2d_bc_type), intent(inout) :: var_out !< variable to copy information to
680 integer, intent(in) :: is !< lower bound of first dimension
681 integer, intent(in) :: ie !< upper bound of first dimension
682 integer, intent(in) :: js !< lower bound of second dimension
683 integer, intent(in) :: je !< upper bound of second dimension
684 character(len=*), intent(in) :: diag_name !< name for diagnostic file--if blank, then
685 !! don't register the fields
686 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
687 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
688 character(len=*), intent(in), optional :: suffix !< optional suffix to make the name identifier unique
689
690 character(len=*), parameter :: error_header =&
691 & '==>Error from coupler_types_mod (coupler_type_copy_3d_2d):'
692
693 if (var_out%num_bcs > 0) then
694 ! It is an error if the number of output fields exceeds zero, because it means this
695 ! type has already been populated.
696 call mpp_error(fatal, trim(error_header) // ' Number of output fields exceeds zero')
697 endif
698
699 if (var_in%num_bcs >= 0)&
700 & call ct_spawn_3d_2d(var_in, var_out, (/ is, is, ie, ie /), (/ js, js, je, je /), suffix)
701
702 if ((var_out%num_bcs > 0) .and. (diag_name .ne. ' '))&
703 & call ct_set_diags_2d(var_out, diag_name, axes, time)
704 end subroutine coupler_type_copy_3d_2d
705
706 !> @brief Copy fields from one coupler type to another. 3-D to 3-D version for generic coupler_type_copy.
707 !!
708 !! @throw FATAL, "Number of output fields exceeds zero"
709 subroutine coupler_type_copy_3d_3d(var_in, var_out, is, ie, js, je, kd,&
710 & diag_name, axes, time, suffix)
711 type(coupler_3d_bc_type), intent(in) :: var_in !< variable to copy information from
712 type(coupler_3d_bc_type), intent(inout) :: var_out !< variable to copy information to
713 integer, intent(in) :: is !< lower bound of first dimension
714 integer, intent(in) :: ie !< upper bound of first dimension
715 integer, intent(in) :: js !< lower bound of second dimension
716 integer, intent(in) :: je !< upper bound of second dimension
717 integer, intent(in) :: kd !< third dimension
718 character(len=*), intent(in) :: diag_name !< name for diagnostic file--if blank, then
719 !! don't register the fields
720 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
721 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
722 character(len=*), intent(in), optional :: suffix !< optional suffix to make the name identifier unique
723
724 character(len=*), parameter :: error_header =&
725 & '==>Error from coupler_types_mod (coupler_type_copy_3d_3d):'
726
727 if (var_out%num_bcs > 0) then
728 ! It is an error if the number of output fields exceeds zero, because it means this
729 ! type has already been populated.
730 call mpp_error(fatal, trim(error_header) // ' Number of output fields exceeds zero')
731 endif
732
733 if (var_in%num_bcs >= 0)&
734 & call ct_spawn_3d_3d(var_in, var_out, (/ is, is, ie, ie /), (/ js, js, je, je /), (/1, kd/), suffix)
735
736 if ((var_out%num_bcs > 0) .and. (diag_name .ne. ' '))&
737 & call ct_set_diags_3d(var_out, diag_name, axes, time)
738 end subroutine coupler_type_copy_3d_3d
739
740
741 !> @brief Generate one coupler type using another as a template. 1-D to 2-D version for generic coupler_type_spawn.
742 !!
743 !! @throw FATAL, "The output type has already been initialized"
744 !! @throw FATAL, "The parent type has not been initialized"
745 !! @throw FATAL, "Disordered i-dimension index bound list"
746 !! @throw FATAL, "Disordered j-dimension index bound list"
747 !! @throw FATAL, "var%bc already assocated"
748 !! @throw FATAL, "var%bc('n')%field already associated"
749 !! @throw FATAL, "var%bc('n')%field('m')%values already associated"
750 subroutine ct_spawn_1d_2d(var_in, var, idim, jdim, suffix, as_needed)
751 type(coupler_1d_bc_type), intent(in) :: var_in !< structure from which to copy information
752 type(coupler_2d_bc_type), intent(inout) :: var !< structure into which to copy information
753 integer, dimension(4), intent(in) :: idim !< The data and computational domain extents of
754 !! the first dimension in a non-decreasing list
755 integer, dimension(4), intent(in) :: jdim !< The data and computational domain extents of
756 !! the second dimension in a non-decreasing list
757 character(len=*), optional, intent(in) :: suffix !< optional suffix to make the name identifier unique
758 logical, optional, intent(in) :: as_needed !< Only do the spawn if the target type (var)
759 !! is not set and the parent type (var_in) is set.
760
761 character(len=*), parameter :: error_header =&
762 & '==>Error from coupler_types_mod (CT_spawn_1d_2d):'
763 character(len=400) :: error_msg
764 integer :: m, n
765
766 if (present(as_needed)) then
767 if (as_needed) then
768 if ((var%set) .or. (.not.var_in%set)) return
769 endif
770 endif
771
772 if (var%set)&
773 & call mpp_error(fatal, trim(error_header) // ' The output type has already been initialized.')
774 if (.not.var_in%set)&
775 & call mpp_error(fatal, trim(error_header) // ' The parent type has not been initialized.')
776
777 ! check only one kind is used
778 if(var_in%num_bcs .gt. 0) then
779 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
780 if( associated(var_in%bc) ) then
781 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both intialized,"//&
782 " only one should be associated per type.")
783 else
784 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both uninitialized,"//&
785 " one must be associated to copy field data.")
786 endif
787 endif
788 endif
789
790 var%num_bcs = var_in%num_bcs
791 var%set = .true.
792
793 if ((idim(1) > idim(2)) .or. (idim(3) > idim(4))) then
794 write (error_msg, *) trim(error_header), ' Disordered i-dimension index bound list ', idim
795 call mpp_error(fatal, trim(error_msg))
796 endif
797 if ((jdim(1) > jdim(2)) .or. (jdim(3) > jdim(4))) then
798 write (error_msg, *) trim(error_header), ' Disordered j-dimension index bound list ', jdim
799 call mpp_error(fatal, trim(error_msg))
800 endif
801 var%isd = idim(1) ; var%isc = idim(2) ; var%iec = idim(3) ; var%ied = idim(4)
802 var%jsd = jdim(1) ; var%jsc = jdim(2) ; var%jec = jdim(3) ; var%jed = jdim(4)
803
804 if (var%num_bcs > 0) then
805 if (associated(var_in%bc)) then
806 if (associated(var%bc)) then
807 call mpp_error(fatal, trim(error_header) // ' var%bc already associated')
808 endif
809 allocate ( var%bc(var%num_bcs) )
810 do n = 1, var%num_bcs
811 var%bc(n)%name = var_in%bc(n)%name
812 var%bc(n)%atm_tr_index = var_in%bc(n)%atm_tr_index
813 var%bc(n)%flux_type = var_in%bc(n)%flux_type
814 var%bc(n)%implementation = var_in%bc(n)%implementation
815 var%bc(n)%ice_restart_file = var_in%bc(n)%ice_restart_file
816 var%bc(n)%ocean_restart_file = var_in%bc(n)%ocean_restart_file
817 var%bc(n)%use_atm_pressure = var_in%bc(n)%use_atm_pressure
818 var%bc(n)%use_10m_wind_speed = var_in%bc(n)%use_10m_wind_speed
819 var%bc(n)%pass_through_ice = var_in%bc(n)%pass_through_ice
820 var%bc(n)%mol_wt = var_in%bc(n)%mol_wt
821 var%bc(n)%num_fields = var_in%bc(n)%num_fields
822 if (associated(var%bc(n)%field)) then
823 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field already associated'
824 call mpp_error(fatal, trim(error_msg))
825 endif
826 allocate ( var%bc(n)%field(var%bc(n)%num_fields) )
827 do m = 1, var%bc(n)%num_fields
828 if (present(suffix)) then
829 var%bc(n)%field(m)%name = trim(var_in%bc(n)%field(m)%name) // trim(suffix)
830 else
831 var%bc(n)%field(m)%name = var_in%bc(n)%field(m)%name
832 endif
833 var%bc(n)%field(m)%long_name = var_in%bc(n)%field(m)%long_name
834 var%bc(n)%field(m)%units = var_in%bc(n)%field(m)%units
835 var%bc(n)%field(m)%may_init = var_in%bc(n)%field(m)%may_init
836 var%bc(n)%field(m)%mean = var_in%bc(n)%field(m)%mean
837 if (associated(var%bc(n)%field(m)%values)) then
838 write (error_msg, *) trim(error_header),&
839 & ' var%bc(', n, ')%field(', m, ')%values already associated'
840 call mpp_error(fatal, trim(error_msg))
841 endif
842 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
843 allocate ( var%bc(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed) )
844 var%bc(n)%field(m)%values(:,:) = 0.0_r8_kind
845 enddo
846 enddo
847 else if( associated(var_in%bc_r4)) then
848 if (associated(var%bc_r4)) then
849 call mpp_error(fatal, trim(error_header) // ' var%bc_r4 already associated')
850 endif
851 allocate ( var%bc_r4(var%num_bcs) )
852 do n = 1, var%num_bcs
853 var%bc_r4(n)%name = var_in%bc_r4(n)%name
854 var%bc_r4(n)%atm_tr_index = var_in%bc_r4(n)%atm_tr_index
855 var%bc_r4(n)%flux_type = var_in%bc_r4(n)%flux_type
856 var%bc_r4(n)%implementation = var_in%bc_r4(n)%implementation
857 var%bc_r4(n)%ice_restart_file = var_in%bc_r4(n)%ice_restart_file
858 var%bc_r4(n)%ocean_restart_file = var_in%bc_r4(n)%ocean_restart_file
859 var%bc_r4(n)%use_atm_pressure = var_in%bc_r4(n)%use_atm_pressure
860 var%bc_r4(n)%use_10m_wind_speed = var_in%bc_r4(n)%use_10m_wind_speed
861 var%bc_r4(n)%pass_through_ice = var_in%bc_r4(n)%pass_through_ice
862 var%bc_r4(n)%mol_wt = var_in%bc_r4(n)%mol_wt
863 var%bc_r4(n)%num_fields = var_in%bc_r4(n)%num_fields
864 if (associated(var%bc_r4(n)%field)) then
865 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field already associated'
866 call mpp_error(fatal, trim(error_msg))
867 endif
868 allocate ( var%bc_r4(n)%field(var%bc_r4(n)%num_fields) )
869 do m = 1, var%bc_r4(n)%num_fields
870 if (present(suffix)) then
871 var%bc_r4(n)%field(m)%name = trim(var_in%bc_r4(n)%field(m)%name) // trim(suffix)
872 else
873 var%bc_r4(n)%field(m)%name = var_in%bc_r4(n)%field(m)%name
874 endif
875 var%bc_r4(n)%field(m)%long_name = var_in%bc_r4(n)%field(m)%long_name
876 var%bc_r4(n)%field(m)%units = var_in%bc_r4(n)%field(m)%units
877 var%bc_r4(n)%field(m)%may_init = var_in%bc_r4(n)%field(m)%may_init
878 var%bc_r4(n)%field(m)%mean = var_in%bc_r4(n)%field(m)%mean
879 if (associated(var%bc_r4(n)%field(m)%values)) then
880 write (error_msg, *) trim(error_header),&
881 & ' var%bc_r4(', n, ')%field(', m, ')%values already associated'
882 call mpp_error(fatal, trim(error_msg))
883 endif
884 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
885 allocate ( var%bc_r4(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed) )
886 var%bc_r4(n)%field(m)%values(:,:) = 0.0_r4_kind
887 enddo
888 enddo
889 else
890 call mpp_error(fatal, error_header//"passed in type has unassociated coupler_field_type"// &
891 " pointers for both bc and bc_r4")
892 endif
893 endif
894 end subroutine ct_spawn_1d_2d
895
896 !> @brief Generate one coupler type using another as a template. 1-D to 3-D version for generic CT_spawn.
897 !!
898 !! @throw FATAL, "The output type has already been initialized"
899 !! @throw FATAL, "The parent type has not been initialized"
900 !! @throw FATAL, "Disordered i-dimension index bound list"
901 !! @throw FATAL, "Disordered j-dimension index bound list"
902 !! @throw FATAL, "var%bc already assocated"
903 !! @throw FATAL, "var%bc('n')%field already associated"
904 !! @throw FATAL, "var%bc('n')%field('m')%values already associated"
905 subroutine ct_spawn_1d_3d(var_in, var, idim, jdim, kdim, suffix, as_needed)
906 type(coupler_1d_bc_type), intent(in) :: var_in !< structure from which to copy information
907 type(coupler_3d_bc_type), intent(inout) :: var !< structure into which to copy information
908 integer, dimension(4), intent(in) :: idim !< The data and computational domain extents of
909 !! the first dimension in a non-decreasing list
910 integer, dimension(4), intent(in) :: jdim !< The data and computational domain extents of
911 !! the second dimension in a non-decreasing list
912 integer, dimension(2), intent(in) :: kdim !< The array extents of the third dimension in
913 !! a non-decreasing list
914 character(len=*), optional, intent(in) :: suffix !< optional suffix to make the name identifier unique
915 logical, optional, intent(in) :: as_needed !< Only do the spawn if the target type (var)
916 !! is not set and the parent type (var_in) is set.
917
918 character(len=*), parameter :: error_header =&
919 & '==>Error from coupler_types_mod (CT_spawn_1d_3d):'
920 character(len=400) :: error_msg
921 integer :: m, n
922
923 if (present(as_needed)) then
924 if (as_needed) then
925 if ((var%set) .or. (.not.var_in%set)) return
926 endif
927 endif
928
929 if (var%set)&
930 & call mpp_error(fatal, trim(error_header) // ' The output type has already been initialized.')
931 if (.not.var_in%set)&
932 & call mpp_error(fatal, trim(error_header) // ' The parent type has not been initialized.')
933
934 ! check only one kind is used
935 if(var_in%num_bcs .gt. 0) then
936 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
937 if( associated(var_in%bc)) then
938 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both intialized,"// &
939 " only one should be associated per type")
940 else
941 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both unintialized,"// &
942 " one must be associated to copy field data")
943 endif
944 endif
945 endif
946
947 var%num_bcs = var_in%num_bcs
948 var%set = .true.
949
950 ! Store the array extents that are to be used with this bc_type.
951 if ((idim(1) > idim(2)) .or. (idim(3) > idim(4))) then
952 write (error_msg, *) trim(error_header), ' Disordered i-dimension index bound list ', idim
953 call mpp_error(fatal, trim(error_msg))
954 endif
955 if ((jdim(1) > jdim(2)) .or. (jdim(3) > jdim(4))) then
956 write (error_msg, *) trim(error_header), ' Disordered j-dimension index bound list ', jdim
957 call mpp_error(fatal, trim(error_msg))
958 endif
959 var%isd = idim(1) ; var%isc = idim(2) ; var%iec = idim(3) ; var%ied = idim(4)
960 var%jsd = jdim(1) ; var%jsc = jdim(2) ; var%jec = jdim(3) ; var%jed = jdim(4)
961 var%ks = kdim(1) ; var%ke = kdim(2)
962
963 if (var%num_bcs > 0) then
964 if (kdim(1) > kdim(2)) then
965 write (error_msg, *) trim(error_header), ' Disordered k-dimension index bound list ', kdim
966 call mpp_error(fatal, trim(error_msg))
967 endif
968 if( associated(var_in%bc)) then
969 if (associated(var%bc)) then
970 call mpp_error(fatal, trim(error_header) // ' var%bc already associated')
971 endif
972 allocate ( var%bc(var%num_bcs) )
973 do n = 1, var%num_bcs
974 var%bc(n)%name = var_in%bc(n)%name
975 var%bc(n)%atm_tr_index = var_in%bc(n)%atm_tr_index
976 var%bc(n)%flux_type = var_in%bc(n)%flux_type
977 var%bc(n)%implementation = var_in%bc(n)%implementation
978 var%bc(n)%ice_restart_file = var_in%bc(n)%ice_restart_file
979 var%bc(n)%ocean_restart_file = var_in%bc(n)%ocean_restart_file
980 var%bc(n)%use_atm_pressure = var_in%bc(n)%use_atm_pressure
981 var%bc(n)%use_10m_wind_speed = var_in%bc(n)%use_10m_wind_speed
982 var%bc(n)%pass_through_ice = var_in%bc(n)%pass_through_ice
983 var%bc(n)%mol_wt = var_in%bc(n)%mol_wt
984 var%bc(n)%num_fields = var_in%bc(n)%num_fields
985 if (associated(var%bc(n)%field)) then
986 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field already associated'
987 call mpp_error(fatal, trim(error_msg))
988 endif
989 allocate ( var%bc(n)%field(var%bc(n)%num_fields) )
990 do m = 1, var%bc(n)%num_fields
991 if (present(suffix)) then
992 var%bc(n)%field(m)%name = trim(var_in%bc(n)%field(m)%name) // trim(suffix)
993 else
994 var%bc(n)%field(m)%name = var_in%bc(n)%field(m)%name
995 endif
996 var%bc(n)%field(m)%long_name = var_in%bc(n)%field(m)%long_name
997 var%bc(n)%field(m)%units = var_in%bc(n)%field(m)%units
998 var%bc(n)%field(m)%may_init = var_in%bc(n)%field(m)%may_init
999 var%bc(n)%field(m)%mean = var_in%bc(n)%field(m)%mean
1000 if (associated(var%bc(n)%field(m)%values)) then
1001 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field(', m, ')%values already associated'
1002 call mpp_error(fatal, trim(error_msg))
1003 endif
1004 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1005 allocate ( var%bc(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed,var%ks:var%ke) )
1006 var%bc(n)%field(m)%values(:,:,:) = 0.0_r8_kind
1007 enddo
1008 enddo
1009 else if(associated(var_in%bc_r4)) then
1010 if (associated(var%bc_r4)) then
1011 call mpp_error(fatal, trim(error_header) // ' var%bc_r4 already associated')
1012 endif
1013 allocate ( var%bc_r4(var%num_bcs) )
1014 do n = 1, var%num_bcs
1015 var%bc_r4(n)%name = var_in%bc_r4(n)%name
1016 var%bc_r4(n)%atm_tr_index = var_in%bc_r4(n)%atm_tr_index
1017 var%bc_r4(n)%flux_type = var_in%bc_r4(n)%flux_type
1018 var%bc_r4(n)%implementation = var_in%bc_r4(n)%implementation
1019 var%bc_r4(n)%ice_restart_file = var_in%bc_r4(n)%ice_restart_file
1020 var%bc_r4(n)%ocean_restart_file = var_in%bc_r4(n)%ocean_restart_file
1021 var%bc_r4(n)%use_atm_pressure = var_in%bc_r4(n)%use_atm_pressure
1022 var%bc_r4(n)%use_10m_wind_speed = var_in%bc_r4(n)%use_10m_wind_speed
1023 var%bc_r4(n)%pass_through_ice = var_in%bc_r4(n)%pass_through_ice
1024 var%bc_r4(n)%mol_wt = var_in%bc_r4(n)%mol_wt
1025 var%bc_r4(n)%num_fields = var_in%bc_r4(n)%num_fields
1026 if (associated(var%bc_r4(n)%field)) then
1027 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field already associated'
1028 call mpp_error(fatal, trim(error_msg))
1029 endif
1030 allocate ( var%bc_r4(n)%field(var%bc_r4(n)%num_fields) )
1031 do m = 1, var%bc_r4(n)%num_fields
1032 if (present(suffix)) then
1033 var%bc_r4(n)%field(m)%name = trim(var_in%bc_r4(n)%field(m)%name) // trim(suffix)
1034 else
1035 var%bc_r4(n)%field(m)%name = var_in%bc_r4(n)%field(m)%name
1036 endif
1037 var%bc_r4(n)%field(m)%long_name = var_in%bc_r4(n)%field(m)%long_name
1038 var%bc_r4(n)%field(m)%units = var_in%bc_r4(n)%field(m)%units
1039 var%bc_r4(n)%field(m)%may_init = var_in%bc_r4(n)%field(m)%may_init
1040 var%bc_r4(n)%field(m)%mean = var_in%bc_r4(n)%field(m)%mean
1041 if (associated(var%bc_r4(n)%field(m)%values)) then
1042 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field(', m, ')%values already associated'
1043 call mpp_error(fatal, trim(error_msg))
1044 endif
1045 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1046 allocate ( var%bc_r4(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed,var%ks:var%ke) )
1047 var%bc_r4(n)%field(m)%values(:,:,:) = 0.0_r4_kind
1048 enddo
1049 enddo
1050 else
1051 call mpp_error(fatal, error_header//"passed in type has unassociated coupler_field_type"// &
1052 " pointers for both bc and bc_r4")
1053 endif
1054 endif
1055 end subroutine ct_spawn_1d_3d
1056
1057
1058 !> @brief Generate one coupler type using another as a template. 2-D to 2-D version for generic CT_spawn.
1059 !!
1060 !! @throw FATAL, "The output type has already been initialized"
1061 !! @throw FATAL, "The parent type has not been initialized"
1062 !! @throw FATAL, "Disordered i-dimension index bound list"
1063 !! @throw FATAL, "Disordered j-dimension index bound list"
1064 !! @throw FATAL, "var%bc already assocated"
1065 !! @throw FATAL, "var%bc('n')%field already associated"
1066 !! @throw FATAL, "var%bc('n')%field('m')%values already associated"
1067 subroutine ct_spawn_2d_2d(var_in, var, idim, jdim, suffix, as_needed)
1068 type(coupler_2d_bc_type), intent(in) :: var_in !< structure from which to copy information
1069 type(coupler_2d_bc_type), intent(inout) :: var !< structure into which to copy information
1070 integer, dimension(4), intent(in) :: idim !< The data and computational domain extents of
1071 !! the first dimension in a non-decreasing list
1072 integer, dimension(4), intent(in) :: jdim !< The data and computational domain extents of
1073 !! the second dimension in a non-decreasing list
1074 character(len=*), optional, intent(in) :: suffix !< optional suffix to make the name identifier unique
1075 logical, optional, intent(in) :: as_needed !< Only do the spawn if the target type (var)
1076 !! is not set and the parent type (var_in) is set.
1077
1078 character(len=*), parameter :: error_header =&
1079 & '==>Error from coupler_types_mod (CT_spawn_2d_2d):'
1080 character(len=400) :: error_msg
1081 integer :: m, n
1082
1083 if (present(as_needed)) then
1084 if (as_needed) then
1085 if ((var%set) .or. (.not.var_in%set)) return
1086 endif
1087 endif
1088
1089 if (var%set)&
1090 & call mpp_error(fatal, trim(error_header) // ' The output type has already been initialized.')
1091 if (.not.var_in%set)&
1092 & call mpp_error(fatal, trim(error_header) // ' The parent type has not been initialized.')
1093
1094 ! check only one kind is used
1095 if(var_in%num_bcs .gt. 0) then
1096 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
1097 if( associated(var_in%bc) ) then
1098 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both intialized,"// &
1099 " only one should be associated per type")
1100 else
1101 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both unintialized,"// &
1102 " one must be associated to copy field data")
1103 endif
1104 endif
1105 endif
1106
1107 var%num_bcs = var_in%num_bcs
1108 var%set = .true.
1109
1110 if ((idim(1) > idim(2)) .or. (idim(3) > idim(4))) then
1111 write (error_msg, *) trim(error_header), ' Disordered i-dimension index bound list ', idim
1112 call mpp_error(fatal, trim(error_msg))
1113 endif
1114 if ((jdim(1) > jdim(2)) .or. (jdim(3) > jdim(4))) then
1115 write (error_msg, *) trim(error_header), ' Disordered j-dimension index bound list ', jdim
1116 call mpp_error(fatal, trim(error_msg))
1117 endif
1118 var%isd = idim(1) ; var%isc = idim(2) ; var%iec = idim(3) ; var%ied = idim(4)
1119 var%jsd = jdim(1) ; var%jsc = jdim(2) ; var%jec = jdim(3) ; var%jed = jdim(4)
1120
1121 if (var%num_bcs > 0) then
1122 if(associated(var_in%bc)) then
1123 if (associated(var%bc)) then
1124 call mpp_error(fatal, trim(error_header) // ' var%bc already associated')
1125 endif
1126 allocate ( var%bc(var%num_bcs) )
1127 do n = 1, var%num_bcs
1128 var%bc(n)%name = var_in%bc(n)%name
1129 var%bc(n)%atm_tr_index = var_in%bc(n)%atm_tr_index
1130 var%bc(n)%flux_type = var_in%bc(n)%flux_type
1131 var%bc(n)%implementation = var_in%bc(n)%implementation
1132 var%bc(n)%ice_restart_file = var_in%bc(n)%ice_restart_file
1133 var%bc(n)%ocean_restart_file = var_in%bc(n)%ocean_restart_file
1134 var%bc(n)%use_atm_pressure = var_in%bc(n)%use_atm_pressure
1135 var%bc(n)%use_10m_wind_speed = var_in%bc(n)%use_10m_wind_speed
1136 var%bc(n)%pass_through_ice = var_in%bc(n)%pass_through_ice
1137 var%bc(n)%mol_wt = var_in%bc(n)%mol_wt
1138 var%bc(n)%num_fields = var_in%bc(n)%num_fields
1139 if (associated(var%bc(n)%field)) then
1140 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field already associated'
1141 call mpp_error(fatal, trim(error_msg))
1142 endif
1143 allocate ( var%bc(n)%field(var%bc(n)%num_fields) )
1144 do m = 1, var%bc(n)%num_fields
1145 if (present(suffix)) then
1146 var%bc(n)%field(m)%name = trim(var_in%bc(n)%field(m)%name) // trim(suffix)
1147 else
1148 var%bc(n)%field(m)%name = var_in%bc(n)%field(m)%name
1149 endif
1150 var%bc(n)%field(m)%long_name = var_in%bc(n)%field(m)%long_name
1151 var%bc(n)%field(m)%units = var_in%bc(n)%field(m)%units
1152 var%bc(n)%field(m)%may_init = var_in%bc(n)%field(m)%may_init
1153 var%bc(n)%field(m)%mean = var_in%bc(n)%field(m)%mean
1154 if (associated(var%bc(n)%field(m)%values)) then
1155 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field(', m, ')%values already associated'
1156 call mpp_error(fatal, trim(error_msg))
1157 endif
1158 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1159 allocate ( var%bc(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed) )
1160 var%bc(n)%field(m)%values(:,:) = 0.0_r8_kind
1161 enddo
1162 enddo
1163 else if (associated(var_in%bc_r4)) then
1164 if (associated(var%bc_r4)) then
1165 call mpp_error(fatal, trim(error_header) // ' var%bc_r4 already associated')
1166 endif
1167 allocate ( var%bc_r4(var%num_bcs) )
1168 do n = 1, var%num_bcs
1169 var%bc_r4(n)%name = var_in%bc_r4(n)%name
1170 var%bc_r4(n)%atm_tr_index = var_in%bc_r4(n)%atm_tr_index
1171 var%bc_r4(n)%flux_type = var_in%bc_r4(n)%flux_type
1172 var%bc_r4(n)%implementation = var_in%bc_r4(n)%implementation
1173 var%bc_r4(n)%ice_restart_file = var_in%bc_r4(n)%ice_restart_file
1174 var%bc_r4(n)%ocean_restart_file = var_in%bc_r4(n)%ocean_restart_file
1175 var%bc_r4(n)%use_atm_pressure = var_in%bc_r4(n)%use_atm_pressure
1176 var%bc_r4(n)%use_10m_wind_speed = var_in%bc_r4(n)%use_10m_wind_speed
1177 var%bc_r4(n)%pass_through_ice = var_in%bc_r4(n)%pass_through_ice
1178 var%bc_r4(n)%mol_wt = var_in%bc_r4(n)%mol_wt
1179 var%bc_r4(n)%num_fields = var_in%bc_r4(n)%num_fields
1180 if (associated(var%bc_r4(n)%field)) then
1181 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field already associated'
1182 call mpp_error(fatal, trim(error_msg))
1183 endif
1184 allocate ( var%bc_r4(n)%field(var%bc_r4(n)%num_fields) )
1185 do m = 1, var%bc_r4(n)%num_fields
1186 if (present(suffix)) then
1187 var%bc_r4(n)%field(m)%name = trim(var_in%bc_r4(n)%field(m)%name) // trim(suffix)
1188 else
1189 var%bc_r4(n)%field(m)%name = var_in%bc_r4(n)%field(m)%name
1190 endif
1191 var%bc_r4(n)%field(m)%long_name = var_in%bc_r4(n)%field(m)%long_name
1192 var%bc_r4(n)%field(m)%units = var_in%bc_r4(n)%field(m)%units
1193 var%bc_r4(n)%field(m)%may_init = var_in%bc_r4(n)%field(m)%may_init
1194 var%bc_r4(n)%field(m)%mean = var_in%bc_r4(n)%field(m)%mean
1195 if (associated(var%bc_r4(n)%field(m)%values)) then
1196 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field(', m, ')%values already associated'
1197 call mpp_error(fatal, trim(error_msg))
1198 endif
1199 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1200 allocate ( var%bc_r4(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed) )
1201 var%bc_r4(n)%field(m)%values(:,:) = 0.0_r4_kind
1202 enddo
1203 enddo
1204 else
1205 call mpp_error(fatal, error_header//"passed in type has unassociated coupler_field_type"// &
1206 " pointers for both bc and bc_r4")
1207 endif
1208 endif
1209 end subroutine ct_spawn_2d_2d
1210
1211 !> @brief Generate one coupler type using another as a template. 2-D to 3-D version for generic CT_spawn.
1212 !!
1213 !! @throw FATAL, "The output type has already been initialized"
1214 !! @throw FATAL, "The parent type has not been initialized"
1215 !! @throw FATAL, "Disordered i-dimension index bound list"
1216 !! @throw FATAL, "Disordered j-dimension index bound list"
1217 !! @throw FATAL, "Disordered k-dimension index bound list"
1218 !! @throw FATAL, "var%bc already assocated"
1219 !! @throw FATAL, "var%bc('n')%field already associated"
1220 !! @throw FATAL, "var%bc('n')%field('m')%values already associated"
1221 subroutine ct_spawn_2d_3d(var_in, var, idim, jdim, kdim, suffix, as_needed)
1222 type(coupler_2d_bc_type), intent(in) :: var_in !< structure from which to copy information
1223 type(coupler_3d_bc_type), intent(inout) :: var !< structure into which to copy information
1224 integer, dimension(4), intent(in) :: idim !< The data and computational domain extents of
1225 !! the first dimension in a non-decreasing list
1226 integer, dimension(4), intent(in) :: jdim !< The data and computational domain extents of
1227 !! the second dimension in a non-decreasing list
1228 integer, dimension(2), intent(in) :: kdim !< The array extents of the third dimension in
1229 !! a non-decreasing list
1230 character(len=*), optional, intent(in) :: suffix !< optional suffix to make the name identifier unique
1231 logical, optional, intent(in) :: as_needed !< Only do the spawn if the target type (var)
1232 !! is not set and the parent type (var_in) is set.
1233
1234 character(len=*), parameter :: error_header =&
1235 & '==>Error from coupler_types_mod (CT_spawn_2d_3d):'
1236 character(len=400) :: error_msg
1237 integer :: m, n
1238
1239 if (present(as_needed)) then
1240 if (as_needed) then
1241 if ((var%set) .or. (.not.var_in%set)) return
1242 endif
1243 endif
1244
1245 if (var%set)&
1246 & call mpp_error(fatal, trim(error_header) // ' The output type has already been initialized.')
1247 if (.not.var_in%set)&
1248 & call mpp_error(fatal, trim(error_header) // ' The parent type has not been initialized.')
1249
1250 if(var_in%num_bcs .gt. 0) then
1251 ! check only one kind is used
1252 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
1253 if( associated(var_in%bc) ) then
1254 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both intialized,"// &
1255 " only one should be associated per type")
1256 else
1257 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both unintialized,"// &
1258 " one must be associated to copy field data")
1259 endif
1260 endif
1261 endif
1262
1263 var%num_bcs = var_in%num_bcs
1264 var%set = .true.
1265
1266 ! Store the array extents that are to be used with this bc_type.
1267 if ((idim(1) > idim(2)) .or. (idim(3) > idim(4))) then
1268 write (error_msg, *) trim(error_header), ' Disordered i-dimension index bound list ', idim
1269 call mpp_error(fatal, trim(error_msg))
1270 endif
1271 if ((jdim(1) > jdim(2)) .or. (jdim(3) > jdim(4))) then
1272 write (error_msg, *) trim(error_header), ' Disordered j-dimension index bound list ', jdim
1273 call mpp_error(fatal, trim(error_msg))
1274 endif
1275 if (kdim(1) > kdim(2)) then
1276 write (error_msg, *) trim(error_header), ' Disordered k-dimension index bound list ', kdim
1277 call mpp_error(fatal, trim(error_msg))
1278 endif
1279 var%isd = idim(1) ; var%isc = idim(2) ; var%iec = idim(3) ; var%ied = idim(4)
1280 var%jsd = jdim(1) ; var%jsc = jdim(2) ; var%jec = jdim(3) ; var%jed = jdim(4)
1281 var%ks = kdim(1) ; var%ke = kdim(2)
1282
1283 if (var%num_bcs > 0) then
1284 if( associated(var_in%bc)) then
1285 if (associated(var%bc)) then
1286 call mpp_error(fatal, trim(error_header) // ' var%bc already associated')
1287 endif
1288 allocate ( var%bc(var%num_bcs) )
1289 do n = 1, var%num_bcs
1290 var%bc(n)%name = var_in%bc(n)%name
1291 var%bc(n)%atm_tr_index = var_in%bc(n)%atm_tr_index
1292 var%bc(n)%flux_type = var_in%bc(n)%flux_type
1293 var%bc(n)%implementation = var_in%bc(n)%implementation
1294 var%bc(n)%ice_restart_file = var_in%bc(n)%ice_restart_file
1295 var%bc(n)%ocean_restart_file = var_in%bc(n)%ocean_restart_file
1296 var%bc(n)%use_atm_pressure = var_in%bc(n)%use_atm_pressure
1297 var%bc(n)%use_10m_wind_speed = var_in%bc(n)%use_10m_wind_speed
1298 var%bc(n)%pass_through_ice = var_in%bc(n)%pass_through_ice
1299 var%bc(n)%mol_wt = var_in%bc(n)%mol_wt
1300 var%bc(n)%num_fields = var_in%bc(n)%num_fields
1301 if (associated(var%bc(n)%field)) then
1302 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field already associated'
1303 call mpp_error(fatal, trim(error_msg))
1304 endif
1305 allocate ( var%bc(n)%field(var%bc(n)%num_fields) )
1306 do m = 1, var%bc(n)%num_fields
1307 if (present(suffix)) then
1308 var%bc(n)%field(m)%name = trim(var_in%bc(n)%field(m)%name) // trim(suffix)
1309 else
1310 var%bc(n)%field(m)%name = var_in%bc(n)%field(m)%name
1311 endif
1312 var%bc(n)%field(m)%long_name = var_in%bc(n)%field(m)%long_name
1313 var%bc(n)%field(m)%units = var_in%bc(n)%field(m)%units
1314 var%bc(n)%field(m)%may_init = var_in%bc(n)%field(m)%may_init
1315 var%bc(n)%field(m)%mean = var_in%bc(n)%field(m)%mean
1316 if (associated(var%bc(n)%field(m)%values)) then
1317 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field(', m, ')%values already associated'
1318 call mpp_error(fatal, trim(error_msg))
1319 endif
1320 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1321 allocate ( var%bc(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed,var%ks:var%ke) )
1322 var%bc(n)%field(m)%values(:,:,:) = 0.0_r8_kind
1323 enddo
1324 enddo
1325 else if(associated(var_in%bc_r4)) then
1326 if (associated(var%bc_r4)) then
1327 call mpp_error(fatal, trim(error_header) // ' var%bc_r4 already associated')
1328 endif
1329 allocate ( var%bc_r4(var%num_bcs) )
1330 do n = 1, var%num_bcs
1331 var%bc_r4(n)%name = var_in%bc_r4(n)%name
1332 var%bc_r4(n)%atm_tr_index = var_in%bc_r4(n)%atm_tr_index
1333 var%bc_r4(n)%flux_type = var_in%bc_r4(n)%flux_type
1334 var%bc_r4(n)%implementation = var_in%bc_r4(n)%implementation
1335 var%bc_r4(n)%ice_restart_file = var_in%bc_r4(n)%ice_restart_file
1336 var%bc_r4(n)%ocean_restart_file = var_in%bc_r4(n)%ocean_restart_file
1337 var%bc_r4(n)%use_atm_pressure = var_in%bc_r4(n)%use_atm_pressure
1338 var%bc_r4(n)%use_10m_wind_speed = var_in%bc_r4(n)%use_10m_wind_speed
1339 var%bc_r4(n)%pass_through_ice = var_in%bc_r4(n)%pass_through_ice
1340 var%bc_r4(n)%mol_wt = var_in%bc_r4(n)%mol_wt
1341 var%bc_r4(n)%num_fields = var_in%bc_r4(n)%num_fields
1342 if (associated(var%bc_r4(n)%field)) then
1343 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field already associated'
1344 call mpp_error(fatal, trim(error_msg))
1345 endif
1346 allocate ( var%bc_r4(n)%field(var%bc_r4(n)%num_fields) )
1347 do m = 1, var%bc_r4(n)%num_fields
1348 if (present(suffix)) then
1349 var%bc_r4(n)%field(m)%name = trim(var_in%bc_r4(n)%field(m)%name) // trim(suffix)
1350 else
1351 var%bc_r4(n)%field(m)%name = var_in%bc_r4(n)%field(m)%name
1352 endif
1353 var%bc_r4(n)%field(m)%long_name = var_in%bc_r4(n)%field(m)%long_name
1354 var%bc_r4(n)%field(m)%units = var_in%bc_r4(n)%field(m)%units
1355 var%bc_r4(n)%field(m)%may_init = var_in%bc_r4(n)%field(m)%may_init
1356 var%bc_r4(n)%field(m)%mean = var_in%bc_r4(n)%field(m)%mean
1357 if (associated(var%bc_r4(n)%field(m)%values)) then
1358 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field(', m, ')%values already associated'
1359 call mpp_error(fatal, trim(error_msg))
1360 endif
1361 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1362 allocate ( var%bc_r4(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed,var%ks:var%ke) )
1363 var%bc_r4(n)%field(m)%values(:,:,:) = 0.0_r4_kind
1364 enddo
1365 enddo
1366 else
1367 call mpp_error(fatal, error_header//"passed in type has unassociated coupler_field_type"// &
1368 " pointers for both bc and bc_r4")
1369 endif
1370 endif
1371 end subroutine ct_spawn_2d_3d
1372
1373 !> @brief Generate one coupler type using another as a template. 3-D to 2-D version for generic CT_spawn.
1374 !!
1375 !! @throw FATAL, "The output type has already been initialized"
1376 !! @throw FATAL, "The parent type has not been initialized"
1377 !! @throw FATAL, "Disordered i-dimension index bound list"
1378 !! @throw FATAL, "Disordered j-dimension index bound list"
1379 !! @throw FATAL, "var%bc already assocated"
1380 !! @throw FATAL, "var%bc('n')%field already associated"
1381 !! @throw FATAL, "var%bc('n')%field('m')%values already associated"
1382 subroutine ct_spawn_3d_2d(var_in, var, idim, jdim, suffix, as_needed)
1383 type(coupler_3d_bc_type), intent(in) :: var_in !< structure from which to copy information
1384 type(coupler_2d_bc_type), intent(inout) :: var !< structure into which to copy information
1385 integer, dimension(4), intent(in) :: idim !< The data and computational domain extents of
1386 !! the first dimension in a non-decreasing list
1387 integer, dimension(4), intent(in) :: jdim !< The data and computational domain extents of
1388 !! the second dimension in a non-decreasing list
1389 character(len=*), optional, intent(in) :: suffix !< optional suffix to make the name identifier unique
1390 logical, optional, intent(in) :: as_needed !< Only do the spawn if the target type (var)
1391 !! is not set and the parent type (var_in) is set.
1392
1393 character(len=*), parameter :: error_header =&
1394 & '==>Error from coupler_types_mod (CT_spawn_3d_2d):'
1395 character(len=400) :: error_msg
1396 integer :: m, n
1397
1398 if (present(as_needed)) then
1399 if (as_needed) then
1400 if ((var%set) .or. (.not.var_in%set)) return
1401 endif
1402 endif
1403
1404 if (var%set)&
1405 & call mpp_error(fatal, trim(error_header) // ' The output type has already been initialized.')
1406 if (.not.var_in%set)&
1407 & call mpp_error(fatal, trim(error_header) // ' The parent type has not been initialized.')
1408
1409 if(var_in%num_bcs .gt. 0) then
1410 ! check only one kind is used
1411 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
1412 if( associated(var_in%bc) ) then
1413 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both intialized,"// &
1414 " only one should be associated per type")
1415 else
1416 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both unintialized,"// &
1417 " one must be associated to copy field data")
1418 endif
1419 endif
1420 endif
1421
1422 var%num_bcs = var_in%num_bcs
1423 var%set = .true.
1424
1425 if ((idim(1) > idim(2)) .or. (idim(3) > idim(4))) then
1426 write (error_msg, *) trim(error_header), ' Disordered i-dimension index bound list ', idim
1427 call mpp_error(fatal, trim(error_msg))
1428 endif
1429 if ((jdim(1) > jdim(2)) .or. (jdim(3) > jdim(4))) then
1430 write (error_msg, *) trim(error_header), ' Disordered j-dimension index bound list ', jdim
1431 call mpp_error(fatal, trim(error_msg))
1432 endif
1433 var%isd = idim(1) ; var%isc = idim(2) ; var%iec = idim(3) ; var%ied = idim(4)
1434 var%jsd = jdim(1) ; var%jsc = jdim(2) ; var%jec = jdim(3) ; var%jed = jdim(4)
1435
1436 if (var%num_bcs > 0) then
1437 ! if using r8_kind reals
1438 if( associated(var_in%bc)) then
1439 if (associated(var%bc)) then
1440 call mpp_error(fatal, trim(error_header) // ' var%bc already associated')
1441 endif
1442 allocate ( var%bc(var%num_bcs) )
1443 do n = 1, var%num_bcs
1444 var%bc(n)%name = var_in%bc(n)%name
1445 var%bc(n)%atm_tr_index = var_in%bc(n)%atm_tr_index
1446 var%bc(n)%flux_type = var_in%bc(n)%flux_type
1447 var%bc(n)%implementation = var_in%bc(n)%implementation
1448 var%bc(n)%ice_restart_file = var_in%bc(n)%ice_restart_file
1449 var%bc(n)%ocean_restart_file = var_in%bc(n)%ocean_restart_file
1450 var%bc(n)%use_atm_pressure = var_in%bc(n)%use_atm_pressure
1451 var%bc(n)%use_10m_wind_speed = var_in%bc(n)%use_10m_wind_speed
1452 var%bc(n)%pass_through_ice = var_in%bc(n)%pass_through_ice
1453 var%bc(n)%mol_wt = var_in%bc(n)%mol_wt
1454 var%bc(n)%num_fields = var_in%bc(n)%num_fields
1455 if (associated(var%bc(n)%field)) then
1456 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field already associated'
1457 call mpp_error(fatal, trim(error_msg))
1458 endif
1459 allocate ( var%bc(n)%field(var%bc(n)%num_fields) )
1460 do m = 1, var%bc(n)%num_fields
1461 if (present(suffix)) then
1462 var%bc(n)%field(m)%name = trim(var_in%bc(n)%field(m)%name) // trim(suffix)
1463 else
1464 var%bc(n)%field(m)%name = var_in%bc(n)%field(m)%name
1465 endif
1466 var%bc(n)%field(m)%long_name = var_in%bc(n)%field(m)%long_name
1467 var%bc(n)%field(m)%units = var_in%bc(n)%field(m)%units
1468 var%bc(n)%field(m)%may_init = var_in%bc(n)%field(m)%may_init
1469 var%bc(n)%field(m)%mean = var_in%bc(n)%field(m)%mean
1470 if (associated(var%bc(n)%field(m)%values)) then
1471 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field(', m, ')%values already associated'
1472 call mpp_error(fatal, trim(error_msg))
1473 endif
1474 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1475 allocate ( var%bc(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed) )
1476 var%bc(n)%field(m)%values(:,:) = 0.0_r8_kind
1477 enddo
1478 enddo
1479 ! if using r4_kind reals (same logic)
1480 else if (associated(var_in%bc_r4)) then
1481 if (associated(var%bc_r4)) then
1482 call mpp_error(fatal, trim(error_header) // ' var%bc_r4 already associated')
1483 endif
1484 allocate ( var%bc_r4(var%num_bcs) )
1485 do n = 1, var%num_bcs
1486 var%bc_r4(n)%name = var_in%bc_r4(n)%name
1487 var%bc_r4(n)%atm_tr_index = var_in%bc_r4(n)%atm_tr_index
1488 var%bc_r4(n)%flux_type = var_in%bc_r4(n)%flux_type
1489 var%bc_r4(n)%implementation = var_in%bc_r4(n)%implementation
1490 var%bc_r4(n)%ice_restart_file = var_in%bc_r4(n)%ice_restart_file
1491 var%bc_r4(n)%ocean_restart_file = var_in%bc_r4(n)%ocean_restart_file
1492 var%bc_r4(n)%use_atm_pressure = var_in%bc_r4(n)%use_atm_pressure
1493 var%bc_r4(n)%use_10m_wind_speed = var_in%bc_r4(n)%use_10m_wind_speed
1494 var%bc_r4(n)%pass_through_ice = var_in%bc_r4(n)%pass_through_ice
1495 var%bc_r4(n)%mol_wt = var_in%bc_r4(n)%mol_wt
1496 var%bc_r4(n)%num_fields = var_in%bc_r4(n)%num_fields
1497 if (associated(var%bc_r4(n)%field)) then
1498 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field already associated'
1499 call mpp_error(fatal, trim(error_msg))
1500 endif
1501 allocate ( var%bc_r4(n)%field(var%bc_r4(n)%num_fields) )
1502 do m = 1, var%bc_r4(n)%num_fields
1503 if (present(suffix)) then
1504 var%bc_r4(n)%field(m)%name = trim(var_in%bc_r4(n)%field(m)%name) // trim(suffix)
1505 else
1506 var%bc_r4(n)%field(m)%name = var_in%bc_r4(n)%field(m)%name
1507 endif
1508 var%bc_r4(n)%field(m)%long_name = var_in%bc_r4(n)%field(m)%long_name
1509 var%bc_r4(n)%field(m)%units = var_in%bc_r4(n)%field(m)%units
1510 var%bc_r4(n)%field(m)%may_init = var_in%bc_r4(n)%field(m)%may_init
1511 var%bc_r4(n)%field(m)%mean = var_in%bc_r4(n)%field(m)%mean
1512 if (associated(var%bc_r4(n)%field(m)%values)) then
1513 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field(', m, ')%values already associated'
1514 call mpp_error(fatal, trim(error_msg))
1515 endif
1516 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1517 allocate ( var%bc_r4(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed) )
1518 var%bc_r4(n)%field(m)%values(:,:) = 0.0_r4_kind
1519 enddo
1520 enddo
1521 else
1522 call mpp_error(fatal, error_header//"passed in type has unassociated coupler_field_type"// &
1523 " pointers for both bc and bc_r4")
1524 endif
1525 endif
1526 end subroutine ct_spawn_3d_2d
1527
1528 !> @brief Generate one coupler type using another as a template. 3-D to 3-D version for generic CT_spawn.
1529 !!
1530 !! @throw FATAL, "The output type has already been initialized"
1531 !! @throw FATAL, "The parent type has not been initialized"
1532 !! @throw FATAL, "Disordered i-dimension index bound list"
1533 !! @throw FATAL, "Disordered j-dimension index bound list"
1534 !! @throw FATAL, "Disordered k-dimension index bound list"
1535 !! @throw FATAL, "var%bc already assocated"
1536 !! @throw FATAL, "var%bc('n')%field already associated"
1537 !! @throw FATAL, "var%bc('n')%field('m')%values already associated"
1538 subroutine ct_spawn_3d_3d(var_in, var, idim, jdim, kdim, suffix, as_needed)
1539 type(coupler_3d_bc_type), intent(in) :: var_in !< structure from which to copy information
1540 type(coupler_3d_bc_type), intent(inout) :: var !< structure into which to copy information
1541 integer, dimension(4), intent(in) :: idim !< The data and computational domain extents of
1542 !! the first dimension in a non-decreasing list
1543 integer, dimension(4), intent(in) :: jdim !< The data and computational domain extents of
1544 !! the second dimension in a non-decreasing list
1545 integer, dimension(2), intent(in) :: kdim !< The array extents of the third dimension in
1546 !! a non-decreasing list
1547 character(len=*), optional, intent(in) :: suffix !< optional suffix to make the name identifier unique
1548 logical, optional, intent(in) :: as_needed !< Only do the spawn if the target type (var)
1549 !! is not set and the parent type (var_in) is set.
1550
1551 character(len=*), parameter :: error_header =&
1552 & '==>Error from coupler_types_mod (CT_spawn_3d_3d):'
1553 character(len=400) :: error_msg
1554 integer :: m, n
1555
1556 if (present(as_needed)) then
1557 if (as_needed) then
1558 if ((var%set) .or. (.not.var_in%set)) return
1559 endif
1560 endif
1561
1562 if (var%set)&
1563 & call mpp_error(fatal, trim(error_header) // ' The output type has already been initialized.')
1564 if (.not.var_in%set)&
1565 & call mpp_error(fatal, trim(error_header) // ' The parent type has not been initialized.')
1566
1567 if(var_in%num_bcs .gt. 0) then
1568 ! check only one kind is used
1569 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
1570 if( associated(var_in%bc)) then
1571 call mpp_error(fatal, error_header//"var_in%bc and var_in%bc_r4 are both initialized,"//&
1572 "only one should be allocated per type")
1573 else
1574 call mpp_error(fatal, error_header//"var_in%bc and var%bc_r4 are both uninitialized,"//&
1575 " one must be associated to copy field data")
1576 endif
1577 endif
1578 endif
1579
1580 var%num_bcs = var_in%num_bcs
1581 var%set = .true.
1582
1583 if ((idim(1) > idim(2)) .or. (idim(3) > idim(4))) then
1584 write (error_msg, *) trim(error_header), ' Disordered i-dimension index bound list ', idim
1585 call mpp_error(fatal, trim(error_msg))
1586 endif
1587 if ((jdim(1) > jdim(2)) .or. (jdim(3) > jdim(4))) then
1588 write (error_msg, *) trim(error_header), ' Disordered j-dimension index bound list ', jdim
1589 call mpp_error(fatal, trim(error_msg))
1590 endif
1591 if (kdim(1) > kdim(2)) then
1592 write (error_msg, *) trim(error_header), ' Disordered k-dimension index bound list ', kdim
1593 call mpp_error(fatal, trim(error_msg))
1594 endif
1595 var%isd = idim(1) ; var%isc = idim(2) ; var%iec = idim(3) ; var%ied = idim(4)
1596 var%jsd = jdim(1) ; var%jsc = jdim(2) ; var%jec = jdim(3) ; var%jed = jdim(4)
1597 var%ks = kdim(1) ; var%ke = kdim(2)
1598
1599 if (var%num_bcs > 0) then
1600 if(associated(var_in%bc)) then
1601 if (associated(var%bc)) then
1602 call mpp_error(fatal, trim(error_header) // ' var%bc already associated')
1603 endif
1604 allocate ( var%bc(var%num_bcs) )
1605 do n = 1, var%num_bcs
1606 var%bc(n)%name = var_in%bc(n)%name
1607 var%bc(n)%atm_tr_index = var_in%bc(n)%atm_tr_index
1608 var%bc(n)%flux_type = var_in%bc(n)%flux_type
1609 var%bc(n)%implementation = var_in%bc(n)%implementation
1610 var%bc(n)%ice_restart_file = var_in%bc(n)%ice_restart_file
1611 var%bc(n)%ocean_restart_file = var_in%bc(n)%ocean_restart_file
1612 var%bc(n)%use_atm_pressure = var_in%bc(n)%use_atm_pressure
1613 var%bc(n)%use_10m_wind_speed = var_in%bc(n)%use_10m_wind_speed
1614 var%bc(n)%pass_through_ice = var_in%bc(n)%pass_through_ice
1615 var%bc(n)%mol_wt = var_in%bc(n)%mol_wt
1616 var%bc(n)%num_fields = var_in%bc(n)%num_fields
1617 if (associated(var%bc(n)%field)) then
1618 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field already associated'
1619 call mpp_error(fatal, trim(error_msg))
1620 endif
1621 allocate ( var%bc(n)%field(var%bc(n)%num_fields) )
1622 do m = 1, var%bc(n)%num_fields
1623 if (present(suffix)) then
1624 var%bc(n)%field(m)%name = trim(var_in%bc(n)%field(m)%name) // trim(suffix)
1625 else
1626 var%bc(n)%field(m)%name = var_in%bc(n)%field(m)%name
1627 endif
1628 var%bc(n)%field(m)%long_name = var_in%bc(n)%field(m)%long_name
1629 var%bc(n)%field(m)%units = var_in%bc(n)%field(m)%units
1630 var%bc(n)%field(m)%may_init = var_in%bc(n)%field(m)%may_init
1631 var%bc(n)%field(m)%mean = var_in%bc(n)%field(m)%mean
1632 if (associated(var%bc(n)%field(m)%values)) then
1633 write (error_msg, *) trim(error_header), ' var%bc(', n, ')%field(', m, ')%values already associated'
1634 call mpp_error(fatal, trim(error_msg))
1635 endif
1636
1637 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1638 allocate ( var%bc(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed,var%ks:var%ke) )
1639 var%bc(n)%field(m)%values(:,:,:) = 0.0_r8_kind
1640 enddo
1641 enddo
1642 else if(associated(var_in%bc_r4)) then
1643 if (associated(var%bc_r4)) then
1644 call mpp_error(fatal, trim(error_header) // ' var%bc_r4 already associated')
1645 endif
1646 allocate ( var%bc_r4(var%num_bcs) )
1647 do n = 1, var%num_bcs
1648 var%bc_r4(n)%name = var_in%bc_r4(n)%name
1649 var%bc_r4(n)%atm_tr_index = var_in%bc_r4(n)%atm_tr_index
1650 var%bc_r4(n)%flux_type = var_in%bc_r4(n)%flux_type
1651 var%bc_r4(n)%implementation = var_in%bc_r4(n)%implementation
1652 var%bc_r4(n)%ice_restart_file = var_in%bc_r4(n)%ice_restart_file
1653 var%bc_r4(n)%ocean_restart_file = var_in%bc_r4(n)%ocean_restart_file
1654 var%bc_r4(n)%use_atm_pressure = var_in%bc_r4(n)%use_atm_pressure
1655 var%bc_r4(n)%use_10m_wind_speed = var_in%bc_r4(n)%use_10m_wind_speed
1656 var%bc_r4(n)%pass_through_ice = var_in%bc_r4(n)%pass_through_ice
1657 var%bc_r4(n)%mol_wt = var_in%bc_r4(n)%mol_wt
1658 var%bc_r4(n)%num_fields = var_in%bc_r4(n)%num_fields
1659 if (associated(var%bc_r4(n)%field)) then
1660 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field already associated'
1661 call mpp_error(fatal, trim(error_msg))
1662 endif
1663 allocate ( var%bc_r4(n)%field(var%bc_r4(n)%num_fields) )
1664 do m = 1, var%bc_r4(n)%num_fields
1665 if (present(suffix)) then
1666 var%bc_r4(n)%field(m)%name = trim(var_in%bc_r4(n)%field(m)%name) // trim(suffix)
1667 else
1668 var%bc_r4(n)%field(m)%name = var_in%bc_r4(n)%field(m)%name
1669 endif
1670 var%bc_r4(n)%field(m)%long_name = var_in%bc_r4(n)%field(m)%long_name
1671 var%bc_r4(n)%field(m)%units = var_in%bc_r4(n)%field(m)%units
1672 var%bc_r4(n)%field(m)%may_init = var_in%bc_r4(n)%field(m)%may_init
1673 var%bc_r4(n)%field(m)%mean = var_in%bc_r4(n)%field(m)%mean
1674 if (associated(var%bc_r4(n)%field(m)%values)) then
1675 write (error_msg, *) trim(error_header), ' var%bc_r4(', n, ')%field(', m, ')%values already associated'
1676 call mpp_error(fatal, trim(error_msg))
1677 endif
1678
1679 ! Note that this may be allocating a zero-sized array, which is legal in Fortran.
1680 allocate ( var%bc_r4(n)%field(m)%values(var%isd:var%ied,var%jsd:var%jed,var%ks:var%ke) )
1681 var%bc_r4(n)%field(m)%values(:,:,:) = 0.0_r4_kind
1682 enddo
1683 enddo
1684 else
1685 call mpp_error(fatal, error_header//"passed in type has unassociated coupler_field_type"// &
1686 " pointers for both bc and bc_r4")
1687 endif
1688 endif
1689 end subroutine ct_spawn_3d_3d
1690
1691
1692 !> @brief Copy all elements of coupler_2d_bc_type.
1693 !! Do a direct copy of the data in all elements of one
1694 !! coupler_2d_bc_type into another. Both must have the same array sizes.
1695 !!
1696 !! @throw FATAL, "bc_index is present and exceeds var_in%num_bcs."
1697 !! @throw FATAL, "field_index is present and exceeds num_fields for var_in%bc(bc_incdx)%name"
1698 !! @throw FATAL, "bc_index must be present if field_index is present."
1699 !! @throw FATAL, "There is an i-direction computational domain size mismatch."
1700 !! @throw FATAL, "There is an j-direction computational domain size mismatch."
1701 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
1702 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
1703 subroutine ct_copy_data_2d(var_in, var, halo_size, bc_index, field_index,&
1704 & exclude_flux_type, only_flux_type, pass_through_ice)
1705 type(coupler_2d_bc_type), intent(in) :: var_in !< BC_type structure with the data to copy
1706 type(coupler_2d_bc_type), intent(inout) :: var !< The recipient BC_type structure
1707 integer, optional, intent(in) :: halo_size !< The extent of the halo to copy; 0 by default
1708 integer, optional, intent(in) :: bc_index !< The index of the boundary condition
1709 !! that is being copied
1710 integer, optional, intent(in) :: field_index !< The index of the field in the
1711 !! boundary condition that is being copied
1712 character(len=*), optional, intent(in) :: exclude_flux_type !< A string describing which types
1713 !! of fluxes to exclude from this copy.
1714 character(len=*), optional, intent(in) :: only_flux_type !< A string describing which types
1715 !! of fluxes to include from this copy.
1716 logical, optional, intent(in) :: pass_through_ice !< If true, only copy BCs whose
1717 !! value of pass_through ice matches this
1718 logical :: copy_bc
1719 integer :: i, j, m, n, n1, n2, halo, i_off, j_off
1720
1721
1722 if (present(bc_index)) then
1723 if (bc_index > var_in%num_bcs)&
1724 & call mpp_error(fatal, "CT_copy_data_2d: bc_index is present and exceeds var_in%num_bcs.")
1725 if (present(field_index)) then
1726 if( associated(var_in%bc)) then
1727 if (field_index > var_in%bc(bc_index)%num_fields)&
1728 & call mpp_error(fatal, "CT_copy_data_2d: field_index is present and exceeds num_fields for" //&
1729 & trim(var_in%bc(bc_index)%name) )
1730 else
1731 if (field_index > var_in%bc_r4(bc_index)%num_fields)&
1732 & call mpp_error(fatal, "CT_copy_data_2d: field_index is present and exceeds num_fields for" //&
1733 & trim(var_in%bc_r4(bc_index)%name) )
1734 endif
1735 endif
1736 elseif (present(field_index)) then
1737 call mpp_error(fatal, "CT_copy_data_2d: bc_index must be present if field_index is present.")
1738 endif
1739
1740 halo = 0
1741 if (present(halo_size)) halo = halo_size
1742
1743 n1 = 1
1744 n2 = var_in%num_bcs
1745 if (present(bc_index)) then
1746 n1 = bc_index
1747 n2 = bc_index
1748 endif
1749
1750 if (n2 >= n1) then
1751 ! A more consciencious implementation would include a more descriptive error messages.
1752 if ((var_in%iec-var_in%isc) /= (var%iec-var%isc))&
1753 & call mpp_error(fatal, "CT_copy_data_2d: There is an i-direction computational domain size mismatch.")
1754 if ((var_in%jec-var_in%jsc) /= (var%jec-var%jsc))&
1755 & call mpp_error(fatal, "CT_copy_data_2d: There is a j-direction computational domain size mismatch.")
1756 if ((var_in%isc-var_in%isd < halo) .or. (var_in%ied-var_in%iec < halo))&
1757 & call mpp_error(fatal, "CT_copy_data_2d: Excessive i-direction halo size for the input structure.")
1758 if ((var_in%jsc-var_in%jsd < halo) .or. (var_in%jed-var_in%jec < halo))&
1759 & call mpp_error(fatal, "CT_copy_data_2d: Excessive j-direction halo size for the input structure.")
1760 if ((var%isc-var%isd < halo) .or. (var%ied-var%iec < halo))&
1761 & call mpp_error(fatal, "CT_copy_data_2d: Excessive i-direction halo size for the output structure.")
1762 if ((var%jsc-var%jsd < halo) .or. (var%jed-var%jec < halo))&
1763 & call mpp_error(fatal, "CT_copy_data_2d: Excessive j-direction halo size for the output structure.")
1764
1765 i_off = var_in%isc - var%isc
1766 j_off = var_in%jsc - var%jsc
1767 endif
1768
1769 if(var_in%set .and. var_in%num_bcs .gt. 0) then
1770 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
1771 if( associated(var_in%bc) ) then
1772 call mpp_error(fatal, "CT_copy_data_2d var_in%bc and var_in%bc_r4 are both intialized,"//&
1773 " only one should be associated per type")
1774 else
1775 call mpp_error(fatal, "CT_copy_data_2d var_in%bc and var_in%bc_r4 are both unintialized,"//&
1776 " one must be associated to copy field data.")
1777 endif
1778 endif
1779 endif
1780
1781 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
1782 if (associated(var_in%bc) .or. var_in%num_bcs .lt. 1) then
1783 do n = n1, n2
1784 copy_bc = .true.
1785 if (copy_bc .and. present(exclude_flux_type))&
1786 & copy_bc = .not.(trim(var%bc(n)%flux_type) == trim(exclude_flux_type))
1787 if (copy_bc .and. present(only_flux_type))&
1788 & copy_bc = (trim(var%bc(n)%flux_type) == trim(only_flux_type))
1789 if (copy_bc .and. present(pass_through_ice))&
1790 & copy_bc = (pass_through_ice .eqv. var%bc(n)%pass_through_ice)
1791 if (.not.copy_bc) cycle
1792
1793 do m = 1, var%bc(n)%num_fields
1794 if (present(field_index)) then
1795 if (m /= field_index) cycle
1796 endif
1797 if ( associated(var%bc(n)%field(m)%values) ) then
1798 do j=var%jsc-halo,var%jec+halo
1799 do i=var%isc-halo,var%iec+halo
1800 var%bc(n)%field(m)%values(i,j) = var_in%bc(n)%field(m)%values(i+i_off,j+j_off)
1801 enddo
1802 enddo
1803 endif
1804 enddo
1805 enddo
1806 else if (associated(var_in%bc_r4)) then
1807 do n = n1, n2
1808 copy_bc = .true.
1809 if (copy_bc .and. present(exclude_flux_type))&
1810 & copy_bc = .not.(trim(var%bc_r4(n)%flux_type) == trim(exclude_flux_type))
1811 if (copy_bc .and. present(only_flux_type))&
1812 & copy_bc = (trim(var%bc_r4(n)%flux_type) == trim(only_flux_type))
1813 if (copy_bc .and. present(pass_through_ice))&
1814 & copy_bc = (pass_through_ice .eqv. var%bc_r4(n)%pass_through_ice)
1815 if (.not.copy_bc) cycle
1816
1817 do m = 1, var%bc_r4(n)%num_fields
1818 if (present(field_index)) then
1819 if (m /= field_index) cycle
1820 endif
1821 if ( associated(var%bc_r4(n)%field(m)%values) ) then
1822 do j=var%jsc-halo,var%jec+halo
1823 do i=var%isc-halo,var%iec+halo
1824 var%bc_r4(n)%field(m)%values(i,j) = var_in%bc_r4(n)%field(m)%values(i+i_off,j+j_off)
1825 enddo
1826 enddo
1827 endif
1828 enddo
1829 enddo
1830 else
1831 call mpp_error(fatal, "CT_copy_data_2d: passed in type has unassociated coupler_field_type"// &
1832 " pointers for both bc and bc_r4")
1833 endif
1834 end subroutine ct_copy_data_2d
1835
1836 !> @brief Copy all elements of coupler_3d_bc_type
1837 !!
1838 !! Do a direct copy of the data in all elements of one
1839 !! coupler_3d_bc_type into another. Both must have the same array sizes.
1840 !!
1841 !! @throw FATAL, "bc_index is present and exceeds var_in%num_bcs."
1842 !! @throw FATAL, "field_index is present and exceeds num_fields for var_in%bc(bc_incdx)%name"
1843 !! @throw FATAL, "bc_index must be present if field_index is present."
1844 !! @throw FATAL, "There is an i-direction computational domain size mismatch."
1845 !! @throw FATAL, "There is an j-direction computational domain size mismatch."
1846 !! @throw FATAL, "There is an k-direction computational domain size mismatch."
1847 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
1848 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
1849 !! @throw FATAL, "Excessive k-direction halo size for the input structure."
1850 subroutine ct_copy_data_3d(var_in, var, halo_size, bc_index, field_index,&
1851 & exclude_flux_type, only_flux_type, pass_through_ice)
1852 type(coupler_3d_bc_type), intent(in) :: var_in !< BC_type structure with the data to copy
1853 type(coupler_3d_bc_type), intent(inout) :: var !< The recipient BC_type structure
1854 integer, optional, intent(in) :: halo_size !< The extent of the halo to copy; 0 by default
1855 integer, optional, intent(in) :: bc_index !< The index of the boundary condition
1856 !! that is being copied
1857 integer, optional, intent(in) :: field_index !< The index of the field in the
1858 !! boundary condition that is being copied
1859 character(len=*), optional, intent(in) :: exclude_flux_type !< A string describing which types
1860 !! of fluxes to exclude from this copy.
1861 character(len=*), optional, intent(in) :: only_flux_type !< A string describing which types
1862 !! of fluxes to include from this copy.
1863 logical, optional, intent(in) :: pass_through_ice !< If true, only copy BCs whose
1864 !! value of pass_through ice matches this
1865 logical :: copy_bc
1866 integer :: i, j, k, m, n, n1, n2, halo, i_off, j_off, k_off
1867
1868 if (present(bc_index)) then
1869 if (bc_index > var_in%num_bcs) &
1870 call mpp_error(fatal, "CT_copy_data_3d: bc_index is present and exceeds var_in%num_bcs.")
1871 if (present(field_index)) then
1872 if( associated(var_in%bc)) then
1873 if (field_index > var_in%bc(bc_index)%num_fields)&
1874 & call mpp_error(fatal, "CT_copy_data_3d: field_index is present and exceeds num_fields for" //&
1875 & trim(var_in%bc(bc_index)%name) )
1876 else
1877 if (field_index > var_in%bc_r4(bc_index)%num_fields)&
1878 & call mpp_error(fatal, "CT_copy_data_3d: field_index is present and exceeds num_fields for" //&
1879 & trim(var_in%bc_r4(bc_index)%name) )
1880 endif
1881 endif
1882 elseif (present(field_index)) then
1883 call mpp_error(fatal, "CT_copy_data_3d: bc_index must be present if field_index is present.")
1884 endif
1885
1886 halo = 0
1887 if (present(halo_size)) halo = halo_size
1888
1889 n1 = 1
1890 n2 = var_in%num_bcs
1891 if (present(bc_index)) then
1892 n1 = bc_index
1893 n2 = bc_index
1894 endif
1895
1896 if (n2 >= n1) then
1897 ! A more consciencious implementation would include a more descriptive error messages.
1898 if ((var_in%iec-var_in%isc) /= (var%iec-var%isc))&
1899 & call mpp_error(fatal, "CT_copy_data_3d: There is an i-direction computational domain size mismatch.")
1900 if ((var_in%jec-var_in%jsc) /= (var%jec-var%jsc))&
1901 & call mpp_error(fatal, "CT_copy_data_3d: There is a j-direction computational domain size mismatch.")
1902 if ((var_in%ke-var_in%ks) /= (var%ke-var%ks))&
1903 & call mpp_error(fatal, "CT_copy_data_3d: There is a k-direction computational domain size mismatch.")
1904 if ((var_in%isc-var_in%isd < halo) .or. (var_in%ied-var_in%iec < halo))&
1905 & call mpp_error(fatal, "CT_copy_data_3d: Excessive i-direction halo size for the input structure.")
1906 if ((var_in%jsc-var_in%jsd < halo) .or. (var_in%jed-var_in%jec < halo))&
1907 & call mpp_error(fatal, "CT_copy_data_3d: Excessive j-direction halo size for the input structure.")
1908 if ((var%isc-var%isd < halo) .or. (var%ied-var%iec < halo))&
1909 & call mpp_error(fatal, "CT_copy_data_3d: Excessive i-direction halo size for the output structure.")
1910 if ((var%jsc-var%jsd < halo) .or. (var%jed-var%jec < halo))&
1911 & call mpp_error(fatal, "CT_copy_data_3d: Excessive j-direction halo size for the output structure.")
1912
1913 i_off = var_in%isc - var%isc
1914 j_off = var_in%jsc - var%jsc
1915 k_off = var_in%ks - var%ks
1916 endif
1917
1918 if(var_in%set .and. var_in%num_bcs .gt. 0) then
1919 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
1920 if( associated(var_in%bc) ) then
1921 call mpp_error(fatal, "CT_copy_data_3d: var_in%bc and var_in%bc_r4 are both intialized,"//&
1922 " only one should be associated per type")
1923 else
1924 call mpp_error(fatal, "CT_copy_data_3d: var_in%bc and var_in%bc_r4 are both unintialized,"//&
1925 " one must be associated to copy field data.")
1926 endif
1927 endif
1928 endif
1929
1930 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
1931 if (associated(var_in%bc) .or. var_in%num_bcs .lt. 1) then
1932 do n = n1, n2
1933 copy_bc = .true.
1934 if (copy_bc .and. present(exclude_flux_type))&
1935 & copy_bc = .not.(trim(var%bc(n)%flux_type) == trim(exclude_flux_type))
1936 if (copy_bc .and. present(only_flux_type))&
1937 & copy_bc = (trim(var%bc(n)%flux_type) == trim(only_flux_type))
1938 if (copy_bc .and. present(pass_through_ice))&
1939 & copy_bc = (pass_through_ice .eqv. var%bc(n)%pass_through_ice)
1940 if (.not.copy_bc) cycle
1941
1942 do m = 1, var_in%bc(n)%num_fields
1943 if (present(field_index)) then
1944 if (m /= field_index) cycle
1945 endif
1946 if ( associated(var%bc(n)%field(m)%values) ) then
1947 do k=var%ks,var%ke
1948 do j=var%jsc-halo,var%jec+halo
1949 do i=var%isc-halo,var%iec+halo
1950 var%bc(n)%field(m)%values(i,j,k) = var_in%bc(n)%field(m)%values(i+i_off,j+j_off,k+k_off)
1951 enddo
1952 enddo
1953 enddo
1954 endif
1955 enddo
1956 enddo
1957 else if (associated(var_in%bc_r4)) then
1958 do n = n1, n2
1959 copy_bc = .true.
1960 if (copy_bc .and. present(exclude_flux_type))&
1961 & copy_bc = .not.(trim(var%bc_r4(n)%flux_type) == trim(exclude_flux_type))
1962 if (copy_bc .and. present(only_flux_type))&
1963 & copy_bc = (trim(var%bc_r4(n)%flux_type) == trim(only_flux_type))
1964 if (copy_bc .and. present(pass_through_ice))&
1965 & copy_bc = (pass_through_ice .eqv. var%bc_r4(n)%pass_through_ice)
1966 if (.not.copy_bc) cycle
1967
1968 do m = 1, var_in%bc_r4(n)%num_fields
1969 if (present(field_index)) then
1970 if (m /= field_index) cycle
1971 endif
1972 if ( associated(var%bc_r4(n)%field(m)%values) ) then
1973 do k=var%ks,var%ke
1974 do j=var%jsc-halo,var%jec+halo
1975 do i=var%isc-halo,var%iec+halo
1976 var%bc_r4(n)%field(m)%values(i,j,k) = var_in%bc_r4(n)%field(m)%values(i+i_off,j+j_off,k+k_off)
1977 enddo
1978 enddo
1979 enddo
1980 endif
1981 enddo
1982 enddo
1983 else
1984 call mpp_error(fatal, "CT_copy_data_3d: passed in type has unassociated coupler_field_type"// &
1985 " pointers for both bc and bc_r4")
1986 endif
1987 end subroutine ct_copy_data_3d
1988
1989 !> @brief Copy all elements of coupler_2d_bc_type to coupler_3d_bc_type
1990 !!
1991 !! Do a direct copy of the data in all elements of one coupler_2d_bc_type into a
1992 !! coupler_3d_bc_type. Both must have the same array sizes for the first two dimensions, while
1993 !! the extend of the 3rd dimension that is being filled may be specified via optional arguments..
1994 !!
1995 !! @throw FATAL, "bc_index is present and exceeds var_in%num_bcs."
1996 !! @throw FATAL, "field_index is present and exceeds num_fields for var_in%bc(bc_incdx)%name"
1997 !! @throw FATAL, "bc_index must be present if field_index is present."
1998 !! @throw FATAL, "There is an i-direction computational domain size mismatch."
1999 !! @throw FATAL, "There is an j-direction computational domain size mismatch."
2000 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
2001 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
2002 subroutine ct_copy_data_2d_3d(var_in, var, halo_size, bc_index, field_index,&
2003 & exclude_flux_type, only_flux_type, pass_through_ice,&
2004 & ind3_start, ind3_end)
2005 type(coupler_2d_bc_type), intent(in) :: var_in !< BC_type structure with the data to copy
2006 type(coupler_3d_bc_type), intent(inout) :: var !< The recipient BC_type structure
2007 integer, optional, intent(in) :: halo_size !< The extent of the halo to copy; 0 by default
2008 integer, optional, intent(in) :: bc_index !< The index of the boundary condition
2009 !! that is being copied
2010 integer, optional, intent(in) :: field_index !< The index of the field in the
2011 !! boundary condition that is being copied
2012 character(len=*), optional, intent(in) :: exclude_flux_type !< A string describing which types
2013 !! of fluxes to exclude from this copy.
2014 character(len=*), optional, intent(in) :: only_flux_type !< A string describing which types
2015 !! of fluxes to include from this copy.
2016 logical, optional, intent(in) :: pass_through_ice !< If true, only copy BCs whose
2017 !! value of pass_through ice matches this
2018 integer, optional, intent(in) :: ind3_start !< The starting value of the 3rd
2019 !! index of the 3d type to fill in.
2020 integer, optional, intent(in) :: ind3_end !< The ending value of the 3rd
2021 !! index of the 3d type to fill in.
2022
2023 logical :: copy_bc
2024 integer :: i, j, k, m, n, n1, n2, halo, i_off, j_off, ks, ke
2025
2026 if (present(bc_index)) then
2027 if (bc_index > var_in%num_bcs)&
2028 & call mpp_error(fatal, "CT_copy_data_2d_3d: bc_index is present and exceeds var_in%num_bcs.")
2029 if (present(field_index)) then ; if (field_index > var_in%bc(bc_index)%num_fields)&
2030 & call mpp_error(fatal, "CT_copy_data_2d_3d: field_index is present and exceeds num_fields for" //&
2031 & trim(var_in%bc(bc_index)%name) )
2032 endif
2033 elseif (present(field_index)) then
2034 call mpp_error(fatal, "CT_copy_data_2d_3d: bc_index must be present if field_index is present.")
2035 endif
2036
2037 halo = 0
2038 if (present(halo_size)) halo = halo_size
2039
2040 n1 = 1
2041 n2 = var_in%num_bcs
2042 if (present(bc_index)) then
2043 n1 = bc_index
2044 n2 = bc_index
2045 endif
2046
2047 if (n2 >= n1) then
2048 ! A more consciencious implementation would include a more descriptive error messages.
2049 if ((var_in%iec-var_in%isc) /= (var%iec-var%isc))&
2050 & call mpp_error(fatal, "CT_copy_data_2d_3d: There is an i-direction computational domain size mismatch.")
2051 if ((var_in%jec-var_in%jsc) /= (var%jec-var%jsc))&
2052 & call mpp_error(fatal, "CT_copy_data_2d_3d: There is a j-direction computational domain size mismatch.")
2053 if ((var_in%isc-var_in%isd < halo) .or. (var_in%ied-var_in%iec < halo))&
2054 & call mpp_error(fatal, "CT_copy_data_2d_3d: Excessive i-direction halo size for the input structure.")
2055 if ((var_in%jsc-var_in%jsd < halo) .or. (var_in%jed-var_in%jec < halo))&
2056 & call mpp_error(fatal, "CT_copy_data_2d_3d: Excessive j-direction halo size for the input structure.")
2057 if ((var%isc-var%isd < halo) .or. (var%ied-var%iec < halo))&
2058 & call mpp_error(fatal, "CT_copy_data_2d_3d: Excessive i-direction halo size for the output structure.")
2059 if ((var%jsc-var%jsd < halo) .or. (var%jed-var%jec < halo))&
2060 & call mpp_error(fatal, "CT_copy_data_2d_3d: Excessive j-direction halo size for the output structure.")
2061 endif
2062
2063 i_off = var_in%isc - var%isc
2064 j_off = var_in%jsc - var%jsc
2065
2066 if(var_in%set .and. var_in%num_bcs .gt. 0) then
2067 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
2068 if( associated(var_in%bc) ) then
2069 call mpp_error(fatal, "CT_copy_data_2d_3d: var_in%bc and var_in%bc_r4 are both intialized,"//&
2070 " only one should be associated per type")
2071 else
2072 call mpp_error(fatal, "CT_copy_data_2d_3d: var_in%bc and var_in%bc_r4 are both unintialized,"//&
2073 " one must be associated to copy field data.")
2074 endif
2075 endif
2076 endif
2077
2078 ! if using r8_kind
2079 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2080 if (associated(var_in%bc) .or. var_in%num_bcs .lt. 1) then
2081 do n = n1, n2
2082 copy_bc = .true.
2083 if (copy_bc .and. present(exclude_flux_type))&
2084 & copy_bc = .not.(trim(var_in%bc(n)%flux_type) == trim(exclude_flux_type))
2085 if (copy_bc .and. present(only_flux_type))&
2086 & copy_bc = (trim(var_in%bc(n)%flux_type) == trim(only_flux_type))
2087 if (copy_bc .and. present(pass_through_ice))&
2088 & copy_bc = (pass_through_ice .eqv. var_in%bc(n)%pass_through_ice)
2089 if (.not.copy_bc) cycle
2090
2091 do m = 1, var_in%bc(n)%num_fields
2092 if (present(field_index)) then
2093 if (m /= field_index) cycle
2094 endif
2095 if ( associated(var%bc(n)%field(m)%values) ) then
2096 ks = var%ks
2097 if (present(ind3_start)) ks = max(ks, ind3_start)
2098 ke = var%ke
2099 if (present(ind3_end)) ke = max(ke, ind3_end)
2100 do k=ks,ke
2101 do j=var%jsc-halo,var%jec+halo
2102 do i=var%isc-halo,var%iec+halo
2103 var%bc(n)%field(m)%values(i,j,k) = var_in%bc(n)%field(m)%values(i+i_off,j+j_off)
2104 enddo
2105 enddo
2106 enddo
2107 endif
2108 enddo
2109 enddo
2110 ! if using r4_kind (same logic)
2111 else if (associated(var_in%bc_r4)) then
2112 do n = n1, n2
2113 copy_bc = .true.
2114 if (copy_bc .and. present(exclude_flux_type))&
2115 & copy_bc = .not.(trim(var_in%bc_r4(n)%flux_type) == trim(exclude_flux_type))
2116 if (copy_bc .and. present(only_flux_type))&
2117 & copy_bc = (trim(var_in%bc_r4(n)%flux_type) == trim(only_flux_type))
2118 if (copy_bc .and. present(pass_through_ice))&
2119 & copy_bc = (pass_through_ice .eqv. var_in%bc_r4(n)%pass_through_ice)
2120 if (.not.copy_bc) cycle
2121
2122 do m = 1, var_in%bc_r4(n)%num_fields
2123 if (present(field_index)) then
2124 if (m /= field_index) cycle
2125 endif
2126 if ( associated(var%bc_r4(n)%field(m)%values) ) then
2127 ks = var%ks
2128 if (present(ind3_start)) ks = max(ks, ind3_start)
2129 ke = var%ke
2130 if (present(ind3_end)) ke = max(ke, ind3_end)
2131 do k=ks,ke
2132 do j=var%jsc-halo,var%jec+halo
2133 do i=var%isc-halo,var%iec+halo
2134 var%bc_r4(n)%field(m)%values(i,j,k) = var_in%bc_r4(n)%field(m)%values(i+i_off,j+j_off)
2135 enddo
2136 enddo
2137 enddo
2138 endif
2139 enddo
2140 enddo
2141 else
2142 call mpp_error(fatal, "CT_copy_data_2d_3d: passed in type has unassociated coupler_field_type"// &
2143 " pointers for both bc and bc_r4")
2144 endif
2145 end subroutine ct_copy_data_2d_3d
2146
2147
2148 !> @brief Redistribute the data in all elements of a coupler_2d_bc_type
2149 !!
2150 !! Redistributes the data in all elements of one coupler_2d_bc_type
2151 !! into another, which may be on different processors with a different decomposition.
2152 !!
2153 !! @throw FATAL, "Mismatch in num_bcs in CT_copy_data_2d."
2154 !! @throw FATAL, "Mismatch in the total number of fields in CT_redistribute_data_2d."
2155 subroutine ct_redistribute_data_2d(var_in, domain_in, var_out, domain_out, complete)
2156 type(coupler_2d_bc_type), intent(in) :: var_in !< BC_type structure with the data to copy (intent in)
2157 type(domain2d), intent(in) :: domain_in !< The FMS domain for the input structure
2158 type(coupler_2d_bc_type), intent(inout) :: var_out !< The recipient BC_type structure (data intent out)
2159 type(domain2d), intent(in) :: domain_out !< The FMS domain for the output structure
2160 logical, optional, intent(in) :: complete !< If true, complete the updates
2161
2162 real(r4_kind), pointer, dimension(:,:) :: null_ptr2D_r4 => null()
2163 real(r8_kind), pointer, dimension(:,:) :: null_ptr2D_r8 => null()
2164 logical :: do_in, do_out, do_complete
2165 integer :: m, n, fc, fc_in, fc_out
2166
2167 do_complete = .true.
2168 if (present(complete)) do_complete = complete
2169
2170 ! Figure out whether this PE has valid input or output fields or both.
2171 do_in = var_in%set
2172 do_out = var_out%set
2173
2174 if(var_in%set .and. var_in%num_bcs .gt. 0) then
2175 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
2176 if( associated(var_in%bc) ) then
2177 call mpp_error(fatal, "CT_redistribute_data_2d: var_in%bc and var_in%bc_r4 are both intialized,"//&
2178 " only one should be associated per type")
2179 else
2180 call mpp_error(fatal, "CT_redistribute_data_2d: var_in%bc and var_in%bc_r4 are both intialized,"//&
2181 " only one must be associated per type to redistribute field data.")
2182 endif
2183 endif
2184 endif
2185
2186 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2187 if(associated(var_in%bc) .or. associated(var_out%bc) .or. var_in%num_bcs .lt. 1) then
2188 fc_in = 0 ; fc_out = 0
2189 if (do_in) then
2190 do n = 1, var_in%num_bcs
2191 do m = 1, var_in%bc(n)%num_fields
2192 if (associated(var_in%bc(n)%field(m)%values)) fc_in = fc_in + 1
2193 enddo
2194 enddo
2195 endif
2196 if (fc_in == 0) do_in = .false.
2197 if (do_out) then
2198 do n = 1, var_out%num_bcs
2199 do m = 1, var_out%bc(n)%num_fields
2200 if (associated(var_out%bc(n)%field(m)%values)) fc_out = fc_out + 1
2201 enddo
2202 enddo
2203 endif
2204 if (fc_out == 0) do_out = .false.
2205
2206 if (do_in .and. do_out) then
2207 if (var_in%num_bcs /= var_out%num_bcs) call mpp_error(fatal,&
2208 & "Mismatch in num_bcs in CT_copy_data_2d.")
2209 if (fc_in /= fc_out) call mpp_error(fatal,&
2210 & "Mismatch in the total number of fields in CT_redistribute_data_2d.")
2211 endif
2212
2213 if (.not.(do_in .or. do_out)) return
2214
2215 fc = 0
2216 if (do_in .and. do_out) then
2217 do n = 1, var_in%num_bcs
2218 do m = 1, var_in%bc(n)%num_fields
2219 if ( associated(var_in%bc(n)%field(m)%values) .neqv.&
2220 & associated(var_out%bc(n)%field(m)%values) ) &
2221 call mpp_error(fatal,&
2222 & "CT_redistribute_data_2d: Mismatch in which var_in and var_out fields are associated"// &
2223 & "Boundary condition:"//string(n)//" Field:"//string(m))
2224 if ( associated(var_in%bc(n)%field(m)%values) ) then
2225 fc = fc + 1
2226 call mpp_redistribute(domain_in, var_in%bc(n)%field(m)%values,&
2227 & domain_out, var_out%bc(n)%field(m)%values,&
2228 & complete=(do_complete.and.(fc==fc_in)) )
2229 endif
2230 enddo
2231 enddo
2232 elseif (do_in) then
2233 do n = 1, var_in%num_bcs
2234 do m = 1, var_in%bc(n)%num_fields
2235 if ( associated(var_in%bc(n)%field(m)%values) ) then
2236 fc = fc + 1
2237 call mpp_redistribute(domain_in, var_in%bc(n)%field(m)%values,&
2238 & domain_out, null_ptr2d_r8,&
2239 & complete=(do_complete.and.(fc==fc_in)) )
2240 endif
2241 enddo
2242 enddo
2243 elseif (do_out) then
2244 do n = 1, var_out%num_bcs
2245 do m = 1, var_out%bc(n)%num_fields
2246 if ( associated(var_out%bc(n)%field(m)%values) ) then
2247 fc = fc + 1
2248 call mpp_redistribute(domain_in, null_ptr2d_r8,&
2249 & domain_out, var_out%bc(n)%field(m)%values,&
2250 & complete=(do_complete.and.(fc==fc_out)) )
2251 endif
2252 enddo
2253 enddo
2254 endif
2255 ! same logic just uses r4_kind
2256 else if( associated(var_in%bc_r4) .or. associated(var_out%bc_r4)) then
2257 fc_in = 0 ; fc_out = 0
2258 if (do_in) then
2259 do n = 1, var_in%num_bcs
2260 do m = 1, var_in%bc_r4(n)%num_fields
2261 if (associated(var_in%bc_r4(n)%field(m)%values)) fc_in = fc_in + 1
2262 enddo
2263 enddo
2264 endif
2265 if (fc_in == 0) do_in = .false.
2266 if (do_out) then
2267 do n = 1, var_out%num_bcs
2268 do m = 1, var_out%bc_r4(n)%num_fields
2269 if (associated(var_out%bc_r4(n)%field(m)%values)) fc_out = fc_out + 1
2270 enddo
2271 enddo
2272 endif
2273 if (fc_out == 0) do_out = .false.
2274
2275 if (do_in .and. do_out) then
2276 if (var_in%num_bcs /= var_out%num_bcs) call mpp_error(fatal,&
2277 & "Mismatch in num_bcs in CT_copy_data_2d.")
2278 if (fc_in /= fc_out) call mpp_error(fatal,&
2279 & "Mismatch in the total number of fields in CT_redistribute_data_2d.")
2280 endif
2281
2282 if (.not.(do_in .or. do_out)) return
2283
2284 fc = 0
2285 if (do_in .and. do_out) then
2286 do n = 1, var_in%num_bcs
2287 do m = 1, var_in%bc_r4(n)%num_fields
2288 if ( associated(var_in%bc_r4(n)%field(m)%values) .neqv.&
2289 & associated(var_out%bc_r4(n)%field(m)%values) ) &
2290 call mpp_error(fatal,&
2291 & "CT_redistribute_data_2d: Mismatch in which var_in and var_out fields are associated"// &
2292 & "Boundary condition:"//string(n)//" Field:"//string(m))
2293 if ( associated(var_in%bc_r4(n)%field(m)%values) ) then
2294 fc = fc + 1
2295 call mpp_redistribute(domain_in, var_in%bc_r4(n)%field(m)%values,&
2296 & domain_out, var_out%bc_r4(n)%field(m)%values,&
2297 & complete=(do_complete.and.(fc==fc_in)) )
2298 endif
2299 enddo
2300 enddo
2301 elseif (do_in) then
2302 do n = 1, var_in%num_bcs
2303 do m = 1, var_in%bc_r4(n)%num_fields
2304 if ( associated(var_in%bc_r4(n)%field(m)%values) ) then
2305 fc = fc + 1
2306 call mpp_redistribute(domain_in, var_in%bc_r4(n)%field(m)%values,&
2307 & domain_out, null_ptr2d_r4,&
2308 & complete=(do_complete.and.(fc==fc_in)) )
2309 endif
2310 enddo
2311 enddo
2312 elseif (do_out) then
2313 do n = 1, var_out%num_bcs
2314 do m = 1, var_out%bc_r4(n)%num_fields
2315 if ( associated(var_out%bc_r4(n)%field(m)%values) ) then
2316 fc = fc + 1
2317 call mpp_redistribute(domain_in, null_ptr2d_r4,&
2318 & domain_out, var_out%bc_r4(n)%field(m)%values,&
2319 & complete=(do_complete.and.(fc==fc_out)) )
2320 endif
2321 enddo
2322 enddo
2323 endif
2324 else
2325 call mpp_error(fatal, "CT_redistribute_data_2d: passed in type has unassociated coupler_field_type"// &
2326 " pointers for both bc and bc_r4")
2327 endif
2328 end subroutine ct_redistribute_data_2d
2329
2330 !> @brief Redistributes the data in all elements of one coupler_2d_bc_type
2331 !!
2332 !! Redistributes the data in all elements of one coupler_2d_bc_type into another, which may be on
2333 !! different processors with a different decomposition.
2334 subroutine ct_redistribute_data_3d(var_in, domain_in, var_out, domain_out, complete)
2335 type(coupler_3d_bc_type), intent(in) :: var_in !< BC_type structure with the data to copy (intent in)
2336 type(domain2d), intent(in) :: domain_in !< The FMS domain for the input structure
2337 type(coupler_3d_bc_type), intent(inout) :: var_out !< The recipient BC_type structure (data intent out)
2338 type(domain2d), intent(in) :: domain_out !< The FMS domain for the output structure
2339 logical, optional, intent(in) :: complete !< If true, complete the updates
2340
2341 real(r4_kind), pointer, dimension(:,:,:) :: null_ptr3D_r4 => null()
2342 real(r8_kind), pointer, dimension(:,:,:) :: null_ptr3D_r8 => null()
2343 logical :: do_in, do_out, do_complete
2344 integer :: m, n, fc, fc_in, fc_out
2345
2346 do_complete = .true.
2347 if (present(complete)) do_complete = complete
2348
2349 ! Figure out whether this PE has valid input or output fields or both.
2350 do_in = var_in%set
2351 do_out = var_out%set
2352
2353 fc_in = 0
2354 fc_out = 0
2355
2356 if(var_in%set .and. var_in%num_bcs .gt. 0) then
2357 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
2358 if( associated(var_in%bc) ) then
2359 call mpp_error(fatal, "CT_redistribute_data_3d: var_in%bc and var_in%bc_r4 are both intialized,"//&
2360 " only one should be associated per type")
2361 else
2362 call mpp_error(fatal, "CT_redistribute_data_3d: var_in%bc and var_in%bc_r4 are both intialized,"//&
2363 " only one must be associated per type to redistribute field data.")
2364 endif
2365 endif
2366 endif
2367
2368 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2369 if( associated(var_in%bc) .or. associated(var_out%bc) .or. var_in%num_bcs .lt. 1) then
2370 if (do_in) then
2371 do n = 1, var_in%num_bcs
2372 do m = 1, var_in%bc(n)%num_fields
2373 if (associated(var_in%bc(n)%field(m)%values)) fc_in = fc_in + 1
2374 enddo
2375 enddo
2376 endif
2377 if (fc_in == 0) do_in = .false.
2378 if (do_out) then
2379 do n = 1, var_out%num_bcs
2380 do m = 1, var_out%bc(n)%num_fields
2381 if (associated(var_out%bc(n)%field(m)%values)) fc_out = fc_out + 1
2382 enddo
2383 enddo
2384 endif
2385 if (fc_out == 0) do_out = .false.
2386
2387 if (do_in .and. do_out) then
2388 if (var_in%num_bcs /= var_out%num_bcs) call mpp_error(fatal,&
2389 & "Mismatch in num_bcs in CT_copy_data_3d.")
2390 if (fc_in /= fc_out) call mpp_error(fatal,&
2391 & "Mismatch in the total number of fields in CT_redistribute_data_3d.")
2392 endif
2393
2394 if (.not.(do_in .or. do_out)) return
2395
2396 fc = 0
2397 if (do_in .and. do_out) then
2398 do n = 1, var_in%num_bcs
2399 do m = 1, var_in%bc(n)%num_fields
2400 if ( associated(var_in%bc(n)%field(m)%values) .neqv.&
2401 & associated(var_out%bc(n)%field(m)%values) )&
2402 & call mpp_error(fatal,&
2403 & "CT_redistribute_data_3d: Mismatch in which var_in and var_out fields are associated"// &
2404 & "Boundary condition:"//string(n)//" Field:"//string(m))
2405 if ( associated(var_in%bc(n)%field(m)%values) ) then
2406 fc = fc + 1
2407 call mpp_redistribute(domain_in, var_in%bc(n)%field(m)%values,&
2408 & domain_out, var_out%bc(n)%field(m)%values,&
2409 & complete=(do_complete.and.(fc==fc_in)) )
2410 endif
2411 enddo
2412 enddo
2413 elseif (do_in) then
2414 do n = 1, var_in%num_bcs
2415 do m = 1, var_in%bc(n)%num_fields
2416 if ( associated(var_in%bc(n)%field(m)%values) ) then
2417 fc = fc + 1
2418 call mpp_redistribute(domain_in, var_in%bc(n)%field(m)%values,&
2419 & domain_out, null_ptr3d_r8,&
2420 & complete=(do_complete.and.(fc==fc_in)) )
2421 endif
2422 enddo
2423 enddo
2424 elseif (do_out) then
2425 do n = 1, var_out%num_bcs
2426 do m = 1, var_out%bc(n)%num_fields
2427 if ( associated(var_out%bc(n)%field(m)%values) ) then
2428 fc = fc + 1
2429 call mpp_redistribute(domain_in, null_ptr3d_r8,&
2430 & domain_out, var_out%bc(n)%field(m)%values,&
2431 & complete=(do_complete.and.(fc==fc_out)) )
2432 endif
2433 enddo
2434 enddo
2435 endif
2436 ! if using r4_kind, bc_r4 will be associated
2437 else if(associated(var_in%bc_r4) .or. associated(var_out%bc_r4)) then
2438 if (do_in) then
2439 do n = 1, var_in%num_bcs
2440 do m = 1, var_in%bc_r4(n)%num_fields
2441 if (associated(var_in%bc_r4(n)%field(m)%values)) fc_in = fc_in + 1
2442 enddo
2443 enddo
2444 endif
2445 if (fc_in == 0) do_in = .false.
2446 if (do_out) then
2447 do n = 1, var_out%num_bcs
2448 do m = 1, var_out%bc_r4(n)%num_fields
2449 if (associated(var_out%bc_r4(n)%field(m)%values)) fc_out = fc_out + 1
2450 enddo
2451 enddo
2452 endif
2453 if (fc_out == 0) do_out = .false.
2454
2455 if (do_in .and. do_out) then
2456 if (var_in%num_bcs /= var_out%num_bcs) call mpp_error(fatal,&
2457 & "Mismatch in num_bcs in CT_copy_data_3d.")
2458 if (fc_in /= fc_out) call mpp_error(fatal,&
2459 & "Mismatch in the total number of fields in CT_redistribute_data_3d.")
2460 endif
2461
2462 if (.not.(do_in .or. do_out)) return
2463
2464 fc = 0
2465 if (do_in .and. do_out) then
2466 do n = 1, var_in%num_bcs
2467 do m = 1, var_in%bc_r4(n)%num_fields
2468 if ( associated(var_in%bc_r4(n)%field(m)%values) .neqv.&
2469 & associated(var_out%bc_r4(n)%field(m)%values) )&
2470 & call mpp_error(fatal,&
2471 & "CT_redistribute_data_3d: Mismatch in which var_in and var_out fields are associated"// &
2472 & "Boundary condition:"//string(n)//" Field:"//string(m))
2473 if ( associated(var_in%bc_r4(n)%field(m)%values) ) then
2474 fc = fc + 1
2475 call mpp_redistribute(domain_in, var_in%bc_r4(n)%field(m)%values,&
2476 & domain_out, var_out%bc_r4(n)%field(m)%values,&
2477 & complete=(do_complete.and.(fc==fc_in)) )
2478 endif
2479 enddo
2480 enddo
2481 elseif (do_in) then
2482 do n = 1, var_in%num_bcs
2483 do m = 1, var_in%bc_r4(n)%num_fields
2484 if ( associated(var_in%bc_r4(n)%field(m)%values) ) then
2485 fc = fc + 1
2486 call mpp_redistribute(domain_in, var_in%bc_r4(n)%field(m)%values,&
2487 & domain_out, null_ptr3d_r4,&
2488 & complete=(do_complete.and.(fc==fc_in)) )
2489 endif
2490 enddo
2491 enddo
2492 elseif (do_out) then
2493 do n = 1, var_out%num_bcs
2494 do m = 1, var_out%bc_r4(n)%num_fields
2495 if ( associated(var_out%bc_r4(n)%field(m)%values) ) then
2496 fc = fc + 1
2497 call mpp_redistribute(domain_in, null_ptr3d_r4,&
2498 & domain_out, var_out%bc_r4(n)%field(m)%values,&
2499 & complete=(do_complete.and.(fc==fc_out)) )
2500 endif
2501 enddo
2502 enddo
2503 endif
2504 else
2505 call mpp_error(fatal, "CT_redistribute_data_3d: passed in type has unassociated coupler_field_type"// &
2506 " pointers for both bc and bc_r4")
2507 endif
2508 end subroutine ct_redistribute_data_3d
2509
2510
2511
2512
2513 !> @brief Increment data in all elements of one coupler_2d_bc_type
2514 !!
2515 !! Do a direct increment of the data in all elements of one coupler_2d_bc_type into another. Both
2516 !! must have the same array sizes.
2517 !!
2518 !! @throw FATAL, "bc_index is present and exceeds var_in%num_bcs."
2519 !! @throw FATAL, "field_index is present and exceeds num_fields for var_in%bc(bc_incdx)%name"
2520 !! @throw FATAL, "bc_index must be present if field_index is present."
2521 !! @throw FATAL, "There is an i-direction computational domain size mismatch."
2522 !! @throw FATAL, "There is an j-direction computational domain size mismatch."
2523 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
2524 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
2525 subroutine ct_increment_data_2d_2d(var_in, var, halo_size, bc_index, field_index,&
2526 & scale_factor, scale_prev, exclude_flux_type, only_flux_type, pass_through_ice)
2527 type(coupler_2d_bc_type), intent(in) :: var_in !< BC_type structure with the data to add to the other type
2528 type(coupler_2d_bc_type), intent(inout) :: var !< The BC_type structure whose fields are being incremented
2529 integer, optional, intent(in) :: halo_size !< The extent of the halo to increment; 0 by default
2530 integer, optional, intent(in) :: bc_index !< The index of the boundary condition
2531 !! that is being copied
2532 integer, optional, intent(in) :: field_index !< The index of the field in the
2533 !! boundary condition that is being copied
2534 real(r8_kind), optional, intent(in) :: scale_factor !< A scaling factor for the data that is being added
2535 real(r8_kind), optional, intent(in) :: scale_prev !< A scaling factor for the data that is already here
2536 character(len=*), optional, intent(in) :: exclude_flux_type !< A string describing which types
2537 !! of fluxes to exclude from this increment.
2538 character(len=*), optional, intent(in) :: only_flux_type !< A string describing which types
2539 !! of fluxes to include from this increment.
2540 logical, optional, intent(in) :: pass_through_ice !< If true, only increment BCs whose
2541 !! value of pass_through ice matches this
2542
2543 real(r8_kind) :: scale, sc_prev
2544 logical :: increment_bc
2545 integer :: i, j, m, n, n1, n2, halo, i_off, j_off
2546
2547 scale = 1.0_r8_kind
2548 if (present(scale_factor)) scale = scale_factor
2549 sc_prev = 1.0_r8_kind
2550 if (present(scale_prev)) sc_prev = scale_prev
2551
2552 if (present(bc_index)) then
2553 if (bc_index > var_in%num_bcs)&
2554 & call mpp_error(fatal, "CT_increment_data_2d_2d: bc_index is present and exceeds var_in%num_bcs.")
2555 if (present(field_index)) then
2556 if( associated(var_in%bc)) then
2557 if (field_index > var_in%bc(bc_index)%num_fields)&
2558 & call mpp_error(fatal, "CT_increment_data_2d_2d: field_index is present and exceeds num_fields for" //&
2559 & trim(var_in%bc(bc_index)%name) )
2560 else
2561 if (field_index > var_in%bc_r4(bc_index)%num_fields)&
2562 & call mpp_error(fatal, "CT_increment_data_2d_2d: field_index is present and exceeds num_fields for" //&
2563 & trim(var_in%bc_r4(bc_index)%name) )
2564 endif
2565 endif
2566 elseif (present(field_index)) then
2567 call mpp_error(fatal, "CT_increment_data_2d_2d: bc_index must be present if field_index is present.")
2568 endif
2569
2570 halo = 0
2571 if (present(halo_size)) halo = halo_size
2572
2573 n1 = 1
2574 n2 = var_in%num_bcs
2575 if (present(bc_index)) then
2576 n1 = bc_index
2577 n2 = bc_index
2578 endif
2579
2580 if (n2 >= n1) then
2581 ! A more consciencious implementation would include a more descriptive error messages.
2582 if ((var_in%iec-var_in%isc) /= (var%iec-var%isc))&
2583 & call mpp_error(fatal, "CT_increment_data_2d: There is an i-direction computational domain size mismatch.")
2584 if ((var_in%jec-var_in%jsc) /= (var%jec-var%jsc))&
2585 & call mpp_error(fatal, "CT_increment_data_2d: There is a j-direction computational domain size mismatch.")
2586 if ((var_in%isc-var_in%isd < halo) .or. (var_in%ied-var_in%iec < halo))&
2587 & call mpp_error(fatal, "CT_increment_data_2d: Excessive i-direction halo size for the input structure.")
2588 if ((var_in%jsc-var_in%jsd < halo) .or. (var_in%jed-var_in%jec < halo))&
2589 & call mpp_error(fatal, "CT_increment_data_2d: Excessive j-direction halo size for the input structure.")
2590 if ((var%isc-var%isd < halo) .or. (var%ied-var%iec < halo))&
2591 & call mpp_error(fatal, "CT_increment_data_2d: Excessive i-direction halo size for the output structure.")
2592 if ((var%jsc-var%jsd < halo) .or. (var%jed-var%jec < halo))&
2593 & call mpp_error(fatal, "CT_increment_data_2d: Excessive j-direction halo size for the output structure.")
2594
2595 i_off = var_in%isc - var%isc
2596 j_off = var_in%jsc - var%jsc
2597 endif
2598
2599 ! check only one kind used
2600 if(var_in%set .and. var_in%num_bcs .gt. 0) then
2601 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
2602 if( associated(var_in%bc) ) then
2603 call mpp_error(fatal, "CT_increment_data_2d_2d: var_in%bc and var_in%bc_r4 are both intialized,"// &
2604 " only one should be associated per type")
2605 else
2606 call mpp_error(fatal, "CT_increment_data_2d_2d: var_in%bc and var_in%bc_r4 are both intialized,"// &
2607 " only one must be associated per type to increment field data.")
2608 endif
2609 endif
2610 endif
2611
2612 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2613 if(associated(var_in%bc) .or. var_in%num_bcs .lt. 1) then
2614 do n = n1, n2
2615 increment_bc = .true.
2616 if (increment_bc .and. present(exclude_flux_type))&
2617 & increment_bc = .not.(trim(var%bc(n)%flux_type) == trim(exclude_flux_type))
2618 if (increment_bc .and. present(only_flux_type))&
2619 & increment_bc = (trim(var%bc(n)%flux_type) == trim(only_flux_type))
2620 if (increment_bc .and. present(pass_through_ice))&
2621 & increment_bc = (pass_through_ice .eqv. var%bc(n)%pass_through_ice)
2622 if (.not.increment_bc) cycle
2623
2624 do m = 1, var_in%bc(n)%num_fields
2625 if (present(field_index)) then
2626 if (m /= field_index) cycle
2627 endif
2628 if ( associated(var%bc(n)%field(m)%values) ) then
2629 do j=var%jsc-halo,var%jec+halo
2630 do i=var%isc-halo,var%iec+halo
2631 var%bc(n)%field(m)%values(i,j) = sc_prev * var%bc(n)%field(m)%values(i,j) +&
2632 & scale * var_in%bc(n)%field(m)%values(i+i_off,j+j_off)
2633 enddo
2634 enddo
2635 endif
2636 enddo
2637 enddo
2638 else if(associated(var_in%bc_r4)) then
2639 do n = n1, n2
2640 increment_bc = .true.
2641 if (increment_bc .and. present(exclude_flux_type))&
2642 & increment_bc = .not.(trim(var%bc_r4(n)%flux_type) == trim(exclude_flux_type))
2643 if (increment_bc .and. present(only_flux_type))&
2644 & increment_bc = (trim(var%bc_r4(n)%flux_type) == trim(only_flux_type))
2645 if (increment_bc .and. present(pass_through_ice))&
2646 & increment_bc = (pass_through_ice .eqv. var%bc_r4(n)%pass_through_ice)
2647 if (.not.increment_bc) cycle
2648
2649 do m = 1, var_in%bc_r4(n)%num_fields
2650 if (present(field_index)) then
2651 if (m /= field_index) cycle
2652 endif
2653 if ( associated(var%bc_r4(n)%field(m)%values) ) then
2654 do j=var%jsc-halo,var%jec+halo
2655 do i=var%isc-halo,var%iec+halo
2656 var%bc_r4(n)%field(m)%values(i,j) = real(sc_prev,r4_kind) * var%bc_r4(n)%field(m)%values(i,j) +&
2657 & real(scale,r4_kind) * var_in%bc_r4(n)%field(m)%values(i+i_off,j+j_off)
2658 enddo
2659 enddo
2660 endif
2661 enddo
2662 enddo
2663 else
2664 call mpp_error(fatal, "CT_increment_data_2d_2d: passed in type has unassociated coupler_field_type"// &
2665 " pointers for both bc and bc_r4")
2666 endif
2667 end subroutine ct_increment_data_2d_2d
2668
2669
2670 !> @brief Increment data in all elements of one coupler_3d_bc_type
2671 !!
2672 !! Do a direct increment of the data in all elements of one coupler_3d_bc_type into another. Both
2673 !! must have the same array sizes.
2674 !!
2675 !! @throw FATAL, "bc_index is present and exceeds var_in%num_bcs."
2676 !! @throw FATAL, "field_index is present and exceeds num_fields for var_in%bc(bc_incdx)%name"
2677 !! @throw FATAL, "bc_index must be present if field_index is present."
2678 !! @throw FATAL, "There is an i-direction computational domain size mismatch."
2679 !! @throw FATAL, "There is an j-direction computational domain size mismatch."
2680 !! @throw FATAL, "There is an k-direction computational domain size mismatch."
2681 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
2682 !! @throw FATAL, "Excessive i-direction halo size for the input structure."
2683 !! @throw FATAL, "Excessive k-direction halo size for the input structure."
2684 subroutine ct_increment_data_3d_3d(var_in, var, halo_size, bc_index, field_index,&
2685 & scale_factor, scale_prev, exclude_flux_type, only_flux_type, pass_through_ice)
2686 type(coupler_3d_bc_type), intent(in) :: var_in !< BC_type structure with the data to add to the other type
2687 type(coupler_3d_bc_type), intent(inout) :: var !< The BC_type structure whose fields are being incremented
2688 integer, optional, intent(in) :: halo_size !< The extent of the halo to copy; 0 by default
2689 integer, optional, intent(in) :: bc_index !< The index of the boundary condition
2690 !! that is being copied
2691 integer, optional, intent(in) :: field_index !< The index of the field in the
2692 !! boundary condition that is being copied
2693 real(r8_kind), optional, intent(in) :: scale_factor !< A scaling factor for the data that is being added
2694 real(r8_kind), optional, intent(in) :: scale_prev !< A scaling factor for the data that is already here
2695 character(len=*), optional, intent(in) :: exclude_flux_type !< A string describing which types
2696 !! of fluxes to exclude from this increment.
2697 character(len=*), optional, intent(in) :: only_flux_type !< A string describing which types of
2698 !! fluxes to include from this increment.
2699 logical, optional, intent(in) :: pass_through_ice !< If true, only increment BCs whose
2700 !! value of pass_through ice matches this
2701
2702 real(r8_kind) :: scale, sc_prev
2703 logical :: increment_bc
2704 integer :: i, j, k, m, n, n1, n2, halo, i_off, j_off, k_off
2705
2706 scale = 1.0_r8_kind
2707 if (present(scale_factor)) scale = scale_factor
2708 sc_prev = 1.0_r8_kind
2709 if (present(scale_prev)) sc_prev = scale_prev
2710
2711 if (present(bc_index)) then
2712 if (bc_index > var_in%num_bcs)&
2713 & call mpp_error(fatal, "CT_increment_data_3d_3d: bc_index is present and exceeds var_in%num_bcs.")
2714 if(associated(var_in%bc)) then
2715 if (present(field_index)) then ; if (field_index > var_in%bc(bc_index)%num_fields)&
2716 & call mpp_error(fatal, "CT_increment_data_3d_3d: field_index is present and exceeds num_fields for" //&
2717 & trim(var_in%bc(bc_index)%name) )
2718 endif
2719 else if(associated(var_in%bc_r4)) then
2720 if (present(field_index)) then ; if (field_index > var_in%bc_r4(bc_index)%num_fields)&
2721 & call mpp_error(fatal, "CT_increment_data_3d_3d: field_index is present and exceeds num_fields for" //&
2722 & trim(var_in%bc_r4(bc_index)%name) )
2723 endif
2724 endif
2725 elseif (present(field_index)) then
2726 call mpp_error(fatal, "CT_increment_data_3d_3d: bc_index must be present if field_index is present.")
2727 endif
2728
2729 halo = 0
2730 if (present(halo_size)) halo = halo_size
2731
2732 n1 = 1
2733 n2 = var_in%num_bcs
2734 if (present(bc_index)) then
2735 n1 = bc_index
2736 n2 = bc_index
2737 endif
2738
2739 if (n2 >= n1) then
2740 ! A more consciencious implementation would include a more descriptive error messages.
2741 if ((var_in%iec-var_in%isc) /= (var%iec-var%isc))&
2742 & call mpp_error(fatal, "CT_increment_data_3d: There is an i-direction computational domain size mismatch.")
2743 if ((var_in%jec-var_in%jsc) /= (var%jec-var%jsc))&
2744 & call mpp_error(fatal, "CT_increment_data_3d: There is a j-direction computational domain size mismatch.")
2745 if ((var_in%ke-var_in%ks) /= (var%ke-var%ks))&
2746 & call mpp_error(fatal, "CT_increment_data_3d: There is a k-direction computational domain size mismatch.")
2747 if ((var_in%isc-var_in%isd < halo) .or. (var_in%ied-var_in%iec < halo))&
2748 & call mpp_error(fatal, "CT_increment_data_3d: Excessive i-direction halo size for the input structure.")
2749 if ((var_in%jsc-var_in%jsd < halo) .or. (var_in%jed-var_in%jec < halo))&
2750 & call mpp_error(fatal, "CT_increment_data_3d: Excessive j-direction halo size for the input structure.")
2751 if ((var%isc-var%isd < halo) .or. (var%ied-var%iec < halo))&
2752 & call mpp_error(fatal, "CT_increment_data_3d: Excessive i-direction halo size for the output structure.")
2753 if ((var%jsc-var%jsd < halo) .or. (var%jed-var%jec < halo))&
2754 & call mpp_error(fatal, "CT_increment_data_3d: Excessive j-direction halo size for the output structure.")
2755
2756 i_off = var_in%isc - var%isc
2757 j_off = var_in%jsc - var%jsc
2758 k_off = var_in%ks - var%ks
2759 endif
2760
2761 ! check only one kind used
2762 if(var_in%set .and. var_in%num_bcs .gt. 0) then
2763 if(associated(var_in%bc) .eqv. associated(var_in%bc_r4)) then
2764 if( associated(var_in%bc) ) then
2765 call mpp_error(fatal, "CT_increment_data_3d_3d: var_in%bc and var_in%bc_r4 are both intialized,"//&
2766 "only one should be associated per type")
2767 else
2768 call mpp_error(fatal, "CT_increment_data_3d_3d: var_in%bc and var_in%bc_r4 are both unintialized,"//&
2769 " only one must be associated per type to increment field data.")
2770 endif
2771 endif
2772 endif
2773
2774 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2775 if(associated(var_in%bc) .or. var_in%num_bcs .lt. 1) then
2776 do n = n1, n2
2777 increment_bc = .true.
2778 if (increment_bc .and. present(exclude_flux_type))&
2779 & increment_bc = .not.(trim(var%bc(n)%flux_type) == trim(exclude_flux_type))
2780 if (increment_bc .and. present(only_flux_type))&
2781 & increment_bc = (trim(var%bc(n)%flux_type) == trim(only_flux_type))
2782 if (increment_bc .and. present(pass_through_ice))&
2783 & increment_bc = (pass_through_ice .eqv. var%bc(n)%pass_through_ice)
2784 if (.not.increment_bc) cycle
2785
2786 do m = 1, var_in%bc(n)%num_fields
2787 if (present(field_index)) then
2788 if (m /= field_index) cycle
2789 endif
2790 if ( associated(var%bc(n)%field(m)%values) ) then
2791 do k=var%ks,var%ke
2792 do j=var%jsc-halo,var%jec+halo
2793 do i=var%isc-halo,var%iec+halo
2794 var%bc(n)%field(m)%values(i,j,k) = sc_prev * var%bc(n)%field(m)%values(i,j,k) +&
2795 & scale * var_in%bc(n)%field(m)%values(i+i_off,j+j_off,k+k_off)
2796 enddo
2797 enddo
2798 enddo
2799 endif
2800 enddo
2801 enddo
2802 else if(associated(var_in%bc_r4)) then
2803 do n = n1, n2
2804 increment_bc = .true.
2805 if (increment_bc .and. present(exclude_flux_type))&
2806 & increment_bc = .not.(trim(var%bc_r4(n)%flux_type) == trim(exclude_flux_type))
2807 if (increment_bc .and. present(only_flux_type))&
2808 & increment_bc = (trim(var%bc_r4(n)%flux_type) == trim(only_flux_type))
2809 if (increment_bc .and. present(pass_through_ice))&
2810 & increment_bc = (pass_through_ice .eqv. var%bc_r4(n)%pass_through_ice)
2811 if (.not.increment_bc) cycle
2812
2813 do m = 1, var_in%bc_r4(n)%num_fields
2814 if (present(field_index)) then
2815 if (m /= field_index) cycle
2816 endif
2817 if ( associated(var%bc_r4(n)%field(m)%values) ) then
2818 do k=var%ks,var%ke
2819 do j=var%jsc-halo,var%jec+halo
2820 do i=var%isc-halo,var%iec+halo
2821 var%bc_r4(n)%field(m)%values(i,j,k) = real(sc_prev,r4_kind) * var%bc_r4(n)%field(m)%values(i,j,k) +&
2822 & real(scale,r4_kind) * var_in%bc_r4(n)%field(m)%values(i+i_off,j+j_off,k+k_off)
2823 enddo
2824 enddo
2825 enddo
2826 endif
2827 enddo
2828 enddo
2829 else
2830 call mpp_error(fatal, "CT_increment_data_3d_3d: passed in type has unassociated coupler_field_type"// &
2831 " pointers for both bc and bc_r4")
2832 endif
2833 end subroutine ct_increment_data_3d_3d
2834
2835 !! @brief Register the diagnostics of a coupler_2d_bc_type
2836 !!
2837 !! @throw FATAL, "axes has less than 2 elements"
2838 subroutine ct_set_diags_2d(var, diag_name, axes, time)
2839 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure for which to register diagnostics
2840 character(len=*), intent(in) :: diag_name !< Module name for diagnostic file--if blank, then
2841 !! don't register the fields
2842 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
2843 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
2844
2845 integer :: m, n
2846
2847 if (diag_name == ' ') return
2848
2849 if (size(axes) < 2) then
2850 call mpp_error(fatal, '==>Error from coupler_types_mod' //&
2851 & '(coupler_types_set_diags_3d): axes has less than 2 elements')
2852 endif
2853
2854 if(var%set .and. var%num_bcs .gt. 0) then
2855 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
2856 if( associated(var%bc) ) then
2857 call mpp_error(fatal, "CT_set_diags_2d: var%bc and var%bc_r4 are both intialized,"//&
2858 "only one should be associated per type")
2859 else
2860 call mpp_error(fatal, "CT_set_diags_2d: var%bc and var%bc_r4 are both intialized,"//&
2861 "one should be associated per type to register fields with diag manager")
2862 endif
2863 endif
2864 endif
2865
2866 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2867 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
2868 do n = 1, var%num_bcs
2869 do m = 1, var%bc(n)%num_fields
2870 var%bc(n)%field(m)%id_diag = register_diag_field(diag_name,&
2871 & var%bc(n)%field(m)%name, axes(1:2), time,&
2872 & var%bc(n)%field(m)%long_name, var%bc(n)%field(m)%units)
2873 enddo
2874 enddo
2875 else if(associated(var%bc_r4)) then
2876 do n = 1, var%num_bcs
2877 do m = 1, var%bc_r4(n)%num_fields
2878 var%bc_r4(n)%field(m)%id_diag = register_diag_field(diag_name,&
2879 & var%bc_r4(n)%field(m)%name, axes(1:2), time,&
2880 & var%bc_r4(n)%field(m)%long_name, var%bc_r4(n)%field(m)%units)
2881 enddo
2882 enddo
2883 else
2884 call mpp_error(fatal, "CT_set_diags_2d: passed in type has unassociated coupler_field_type"// &
2885 " pointers for both bc and bc_r4")
2886 endif
2887
2888
2889 end subroutine ct_set_diags_2d
2890
2891 !> @brief Register the diagnostics of a coupler_3d_bc_type.
2892 !!
2893 !! @throw FATAL, "axes has less than 3 elements"
2894 subroutine ct_set_diags_3d(var, diag_name, axes, time)
2895 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure for which to register diagnostics
2896 character(len=*), intent(in) :: diag_name !< Module name for diagnostic file--if blank, then
2897 !! don't register the fields
2898 integer, dimension(:), intent(in) :: axes !< array of axes identifiers for diagnostic variable registration
2899 type(time_type), intent(in) :: time !< model time variable for registering diagnostic field
2900
2901 integer :: m, n
2902
2903 if (diag_name == ' ') return
2904
2905 if (size(axes) < 3) then
2906 call mpp_error(fatal, '==>Error from coupler_types_mod' //&
2907 & '(coupler_types_set_diags_3d): axes has less than 3 elements')
2908 endif
2909
2910 if(var%set .and. var%num_bcs .gt. 0) then
2911 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
2912 if( associated(var%bc) ) then
2913 call mpp_error(fatal, "CT_set_diags_3d: var%bc and var%bc_r4 are both intialized,"//&
2914 "only one should be associated per type")
2915 else
2916 call mpp_error(fatal, "CT_set_diags_3d: var%bc and var%bc_r4 are both unintialized,"//&
2917 "one should be associated per type to register fields with diag manager")
2918 endif
2919 endif
2920 endif
2921
2922 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2923 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
2924 do n = 1, var%num_bcs
2925 do m = 1, var%bc(n)%num_fields
2926 var%bc(n)%field(m)%id_diag = register_diag_field(diag_name,&
2927 & var%bc(n)%field(m)%name, axes(1:3), time,&
2928 & var%bc(n)%field(m)%long_name, var%bc(n)%field(m)%units )
2929 enddo
2930 enddo
2931 else if(associated(var%bc_r4)) then
2932 do n = 1, var%num_bcs
2933 do m = 1, var%bc_r4(n)%num_fields
2934 var%bc_r4(n)%field(m)%id_diag = register_diag_field(diag_name,&
2935 & var%bc_r4(n)%field(m)%name, axes(1:3), time,&
2936 & var%bc_r4(n)%field(m)%long_name, var%bc_r4(n)%field(m)%units )
2937 enddo
2938 enddo
2939 else
2940 call mpp_error(fatal, "CT_set_diags_3d: passed in type has unassociated coupler_field_type"// &
2941 " pointers for both bc and bc_r4")
2942 endif
2943 end subroutine ct_set_diags_3d
2944
2945
2946 !> @brief Write out all diagnostics of elements of a coupler_2d_bc_type
2947 subroutine ct_send_data_2d(var, Time, return_statuses)
2948 type(coupler_2d_bc_type), intent(in) :: var !< BC_type structure with the diagnostics to write
2949 type(time_type), intent(in) :: time !< The current model time
2950 logical, allocatable, optional, intent(out) :: return_statuses(:,:) !< Return status of send data calls
2951 !! first index is index of boundary condition
2952 !! second index is field/value within that boundary condition
2953
2954 integer :: m, n
2955 logical :: used
2956
2957 if(var%set .and. var%num_bcs .gt. 0) then
2958 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
2959 if( associated(var%bc) ) then
2960 call mpp_error(fatal, "CT_send_data_2d: var%bc and var%bc_r4 are both intialized,"//&
2961 "only one should be associated per type")
2962 else
2963 call mpp_error(fatal, "CT_send_data_2d: var%bc and var%bc_r4 are both unintialized,"//&
2964 "one should be associated per type to send data to diag fields")
2965 endif
2966 endif
2967 endif
2968
2969 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
2970 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
2971
2972 ! allocate array for returned send data statuses
2973 if( present(return_statuses) .and. var%num_bcs .gt. 0) then
2974 allocate(return_statuses(var%num_bcs, var%bc(1)%num_fields))
2975 endif
2976
2977 do n = 1, var%num_bcs
2978 do m = 1, var%bc(n)%num_fields
2979 if (var%bc(n)%field(m)%id_diag > 0) then
2980 used = send_data(var%bc(n)%field(m)%id_diag, var%bc(n)%field(m)%values, time)
2981 if(allocated(return_statuses)) return_statuses(n,m) = used
2982 endif
2983 enddo
2984 enddo
2985
2986 else if(associated(var%bc_r4)) then
2987
2988 ! allocate array for returned send data statuses
2989 if( present(return_statuses) .and. var%num_bcs .gt. 0) then
2990 allocate(return_statuses(var%num_bcs, var%bc_r4(1)%num_fields))
2991 endif
2992
2993 do n = 1, var%num_bcs
2994 do m = 1, var%bc_r4(n)%num_fields
2995 if (var%bc_r4(n)%field(m)%id_diag > 0) then
2996 used = send_data(var%bc_r4(n)%field(m)%id_diag, var%bc_r4(n)%field(m)%values, time)
2997 if(allocated(return_statuses)) return_statuses(n,m) = used
2998 endif
2999 enddo
3000 enddo
3001 else
3002 call mpp_error(fatal, "CT_send_data_2d: passed in type has unassociated coupler_field_type"// &
3003 " pointers for both bc and bc_r4")
3004 endif
3005 end subroutine ct_send_data_2d
3006
3007 !> @brief Write out all diagnostics of elements of a coupler_3d_bc_type
3008 subroutine ct_send_data_3d(var, Time, return_statuses)
3009 type(coupler_3d_bc_type), intent(in) :: var !< BC_type structure with the diagnostics to write
3010 type(time_type), intent(in) :: time !< The current model time
3011 logical, allocatable, optional, intent(out) :: return_statuses(:,:) !< Return status of send data calls
3012 !! first index is index of boundary condition
3013 !! second index is field/value within that boundary condition
3014
3015 integer :: m, n
3016 logical :: used
3017
3018 if(var%set .and. var%num_bcs .gt. 0) then
3019 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3020 if( associated(var%bc) ) then
3021 call mpp_error(fatal, "CT_send_data_3d: var%bc and var%bc_r4 are both intialized,"//&
3022 "only one should be associated per type")
3023 else
3024 call mpp_error(fatal, "CT_send_data_3d: var%bc and var%bc_r4 are both unintialized,"//&
3025 "one should be associated per type to send data to diag fields")
3026 endif
3027 endif
3028 endif
3029
3030 ! num_bcs .lt. 1 -> loop doesn't run but shouldn't error out
3031 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3032
3033 ! allocate array for returned send data statuses
3034 if( present(return_statuses) .and. var%num_bcs .gt. 0) then
3035 allocate(return_statuses(var%num_bcs, var%bc(1)%num_fields))
3036 endif
3037
3038 do n = 1, var%num_bcs
3039 do m = 1, var%bc(n)%num_fields
3040 if (var%bc(n)%field(m)%id_diag > 0) then
3041 used = send_data(var%bc(n)%field(m)%id_diag, var%bc(n)%field(m)%values, time)
3042 if(allocated(return_statuses)) return_statuses(n,m) = used
3043 endif
3044 enddo
3045 enddo
3046 else if(associated(var%bc_r4)) then
3047
3048 ! allocate array for returned send data statuses
3049 if( present(return_statuses) .and. var%num_bcs .gt. 0) then
3050 allocate(return_statuses(var%num_bcs, var%bc_r4(1)%num_fields))
3051 endif
3052
3053 do n = 1, var%num_bcs
3054 do m = 1, var%bc_r4(n)%num_fields
3055 if (var%bc_r4(n)%field(m)%id_diag > 0) then
3056 used = send_data(var%bc_r4(n)%field(m)%id_diag, var%bc_r4(n)%field(m)%values, time)
3057 if(allocated(return_statuses)) return_statuses(n,m) = used
3058 endif
3059 enddo
3060 enddo
3061 else
3062 call mpp_error(fatal, "CT_send_data_3d: passed in type has unassociated coupler_field_type"// &
3063 " pointers for both bc and bc_r4")
3064 endif
3065 end subroutine ct_send_data_3d
3066
3067 !! @brief Register the fields in a coupler_2d_bc_type to be saved in restart files
3068 !! This subroutine registers the fields in a coupler_2d_bc_type to be saved in restart files
3069 !! specified in the field table.
3070 subroutine ct_register_restarts_2d(var, bc_rest_files, num_rest_files, mpp_domain, to_read, ocean_restart, directory)
3071 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure to be registered for restarts
3072 type(fmsnetcdfdomainfile_t), dimension(:), pointer :: bc_rest_files !< Structures describing the restart files
3073 integer, intent(out) :: num_rest_files !< The number of restart files to use
3074 type(domain2d), intent(in) :: mpp_domain !< The FMS domain to use for this registration call
3075 logical, intent(in) :: to_read !< Flag indicating if reading/writing a file
3076 logical, optional,intent(in) :: ocean_restart !< If true, use the ocean restart file name.
3077 character(len=*),optional,intent(in) :: directory !< Directory where to open the file
3078
3079 character(len=FMS_FILE_LEN), dimension(max(1,var%num_bcs)) :: rest_file_names
3080 character(len=FMS_FILE_LEN) :: file_nm
3081 logical :: ocn_rest
3082 integer :: f, n, m
3083
3084 character(len=20), allocatable, dimension(:) :: dim_names !< Array of dimension names
3085 character(len=20) :: io_type !< flag indicating io type: "read" "overwrite"
3086 logical, dimension(max(1,var%num_bcs)) :: file_is_open !< flag indicating if file is open
3087 character(len=FMS_PATH_LEN) :: dir !< Directory where to open the file
3088
3089 if(var%set .and. var%num_bcs .gt. 0) then
3090 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3091 if( associated(var%bc) ) then
3092 call mpp_error(fatal, "CT_register_restarts_2d: var%bc and var%bc_r4 are both intialized,"//&
3093 "only one should be associated per type")
3094 else
3095 call mpp_error(fatal, "CT_register_restarts_2d: var%bc and var%bc_r4 are both unintialized,"//&
3096 "one should be associated per type to register restart fields")
3097 endif
3098 endif
3099 endif
3100
3101 ocn_rest = .true.
3102 if (present(ocean_restart)) ocn_rest = ocean_restart
3103
3104 if (present(directory)) dir = trim(directory)
3105
3106 if (to_read) then
3107 io_type = "read"
3108 if (.not. present(directory)) dir = "INPUT/"
3109 else
3110 io_type = "overwrite"
3111 if (.not. present(directory)) dir = "RESTART/"
3112 endif
3113
3114 num_rest_files = 0
3115
3116 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3117 ! Determine the number and names of the restart files
3118 do n = 1, var%num_bcs
3119 if (var%bc(n)%num_fields <= 0) cycle
3120 file_nm = trim(var%bc(n)%ice_restart_file)
3121 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
3122 do f = 1, num_rest_files
3123 if (trim(file_nm) == trim(rest_file_names(f))) exit
3124 enddo
3125 if (f>num_rest_files) then
3126 num_rest_files = num_rest_files + 1
3127 rest_file_names(f) = trim(file_nm)
3128 endif
3129 enddo
3130
3131 if (num_rest_files == 0) return
3132
3133 allocate(bc_rest_files(num_rest_files))
3134
3135 !< Open the files
3136 do n = 1, num_rest_files
3137 file_is_open(n) = open_file(bc_rest_files(n), trim(dir)//rest_file_names(n), io_type, mpp_domain, &
3138 & is_restart=.true.)
3139 if (file_is_open(n)) then
3140 call register_axis_wrapper(bc_rest_files(n), to_read=to_read)
3141 endif
3142 enddo
3143
3144 ! Register the fields with the restart files
3145 do n = 1, var%num_bcs
3146 if (var%bc(n)%num_fields <= 0) cycle
3147
3148 file_nm = trim(var%bc(n)%ice_restart_file)
3149 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
3150 do f = 1, num_rest_files
3151 if (trim(file_nm) == trim(rest_file_names(f))) exit
3152 enddo
3153
3154 var%bc(n)%fms2_io_rest_type => bc_rest_files(f)
3155
3156 do m = 1, var%bc(n)%num_fields
3157 if (file_is_open(f)) then
3158 if( to_read .and. variable_exists(bc_rest_files(f), var%bc(n)%field(m)%name)) then
3159 !< If reading get the dimension names from the file
3160 allocate(dim_names(get_variable_num_dimensions(bc_rest_files(f), var%bc(n)%field(m)%name)))
3161 call get_variable_dimension_names(bc_rest_files(f), &
3162 & var%bc(n)%field(m)%name, dim_names)
3163 else
3164 !< If writing use dummy dimension names
3165 allocate(dim_names(3))
3166 dim_names(1) = "xaxis_1"
3167 dim_names(2) = "yaxis_1"
3168 dim_names(3) = "Time"
3169 endif !< to_read
3170
3171 call register_restart_field(bc_rest_files(f),&
3172 & var%bc(n)%field(m)%name, var%bc(n)%field(m)%values, dim_names, &
3173 & is_optional=var%bc(n)%field(m)%may_init )
3174
3175 deallocate(dim_names)
3176 endif !< If file_is_open
3177 enddo !< num_fields
3178 enddo !< num_bcs
3179 else if(associated(var%bc_r4)) then
3180 ! Determine the number and names of the restart files
3181 do n = 1, var%num_bcs
3182 if (var%bc_r4(n)%num_fields <= 0) cycle
3183 file_nm = trim(var%bc_r4(n)%ice_restart_file)
3184 if (ocn_rest) file_nm = trim(var%bc_r4(n)%ocean_restart_file)
3185 do f = 1, num_rest_files
3186 if (trim(file_nm) == trim(rest_file_names(f))) exit
3187 enddo
3188 if (f>num_rest_files) then
3189 num_rest_files = num_rest_files + 1
3190 rest_file_names(f) = trim(file_nm)
3191 endif
3192 enddo
3193
3194 if (num_rest_files == 0) return
3195
3196 allocate(bc_rest_files(num_rest_files))
3197
3198 !< Open the files
3199 do n = 1, num_rest_files
3200 file_is_open(n) = open_file(bc_rest_files(n), trim(dir)//rest_file_names(n), io_type, mpp_domain, &
3201 & is_restart=.true.)
3202 if (file_is_open(n)) then
3203 call register_axis_wrapper(bc_rest_files(n), to_read=to_read)
3204 endif
3205 enddo
3206
3207 ! Register the fields with the restart files
3208 do n = 1, var%num_bcs
3209 if (var%bc_r4(n)%num_fields <= 0) cycle
3210
3211 file_nm = trim(var%bc_r4(n)%ice_restart_file)
3212 if (ocn_rest) file_nm = trim(var%bc_r4(n)%ocean_restart_file)
3213 do f = 1, num_rest_files
3214 if (trim(file_nm) == trim(rest_file_names(f))) exit
3215 enddo
3216
3217 var%bc_r4(n)%fms2_io_rest_type => bc_rest_files(f)
3218
3219 do m = 1, var%bc_r4(n)%num_fields
3220 if (file_is_open(f)) then
3221 if( to_read .and. variable_exists(bc_rest_files(f), var%bc_r4(n)%field(m)%name)) then
3222 !< If reading get the dimension names from the file
3223 allocate(dim_names(get_variable_num_dimensions(bc_rest_files(f), var%bc_r4(n)%field(m)%name)))
3224 call get_variable_dimension_names(bc_rest_files(f), &
3225 & var%bc_r4(n)%field(m)%name, dim_names)
3226 else
3227 !< If writing use dummy dimension names
3228 allocate(dim_names(3))
3229 dim_names(1) = "xaxis_1"
3230 dim_names(2) = "yaxis_1"
3231 dim_names(3) = "Time"
3232 endif !< to_read
3233
3234 call register_restart_field(bc_rest_files(f),&
3235 & var%bc_r4(n)%field(m)%name, var%bc_r4(n)%field(m)%values, dim_names, &
3236 & is_optional=var%bc_r4(n)%field(m)%may_init )
3237
3238 deallocate(dim_names)
3239 endif !< If file_is_open
3240 enddo !< num_fields
3241 enddo !< num_bcs
3242 else
3243 call mpp_error(fatal, "CT_register_restarts_2d: passed in type has unassociated coupler_field_type"// &
3244 " pointers for both bc and bc_r4")
3245 endif ! associated(var%bc/r4)
3246
3247 end subroutine ct_register_restarts_2d
3248
3249 !< If reading a restart, register the dimensions that are in the file
3250 subroutine register_axis_wrapper_read(fileobj)
3251 type(fmsnetcdfdomainfile_t), intent(inout) :: fileobj !< Domain decomposed fileobj
3252
3253 character(len=20), dimension(:), allocatable :: file_dim_names !< Array of dimension names
3254 integer :: i !< No description
3255 integer :: dim_size !< Size of the dimension
3256 integer :: ndims !< Number of dimensions in the file
3257 logical :: is_domain_decomposed !< Flag indication if domain decomposed
3258 character(len=1) :: buffer !< string buffer
3259
3260 ndims = get_num_dimensions(fileobj)
3261 allocate(file_dim_names(ndims))
3262
3263 call get_dimension_names(fileobj, file_dim_names)
3264
3265 do i = 1, ndims
3266 is_domain_decomposed = .false.
3267
3268 !< Check if the dimension is also a variable
3269 if (variable_exists(fileobj, file_dim_names(i))) then
3270
3271 !< If the variable exists look for the "cartesian_axis" or "axis" variable attribute
3272 if (variable_att_exists(fileobj, file_dim_names(i), "axis")) then
3273 call get_variable_attribute(fileobj, file_dim_names(i), "axis", buffer)
3274
3275 !< If the attribute exists and it is "x" or "y" register it as a domain decomposed dimension
3276 if (lowercase(buffer) .eq. "x" .or. lowercase(buffer) .eq. "y" ) then
3277 is_domain_decomposed = .true.
3278 call register_axis(fileobj, file_dim_names(i), buffer)
3279 endif
3280
3281 else if (variable_att_exists(fileobj, file_dim_names(i), "cartesian_axis")) then
3282 call get_variable_attribute(fileobj, file_dim_names(i), "cartesian_axis", buffer)
3283
3284 !< If the attribute exists and it "x" or "y" register it as a domain decomposed dimension
3285 if (lowercase(buffer) .eq. "x" .or. lowercase(buffer) .eq. "y" ) then
3286 is_domain_decomposed = .true.
3287 call register_axis(fileobj, file_dim_names(i), buffer)
3288 endif
3289
3290 endif !< If variable attribute exists
3291 endif !< If variable exists
3292
3293 if (.not. is_domain_decomposed) then
3294 call get_dimension_size(fileobj, file_dim_names(i), dim_size)
3295 call register_axis(fileobj, file_dim_names(i), dim_size)
3296 endif
3297
3298 end do
3299
3300 end subroutine register_axis_wrapper_read
3301
3302 !< If writting a restart, register the variables with dummy axis names
3303 subroutine register_axis_wrapper_write(fileobj, nz)
3304 type(fmsnetcdfdomainfile_t), intent(inout) :: fileobj !< Domain decomposed fileobj
3305 integer, intent(in), optional :: nz !< length of the z dimension
3306
3307 character(len=20) :: dim_names(4) !< Array of dimension names
3308
3309 dim_names(1) = "xaxis_1"
3310 dim_names(2) = "yaxis_1"
3311
3312 call register_axis(fileobj, dim_names(1), "x")
3313 call register_axis(fileobj, dim_names(2), "y")
3314
3315 !< If nz is present register a zaxis
3316 if (.not. present(nz)) then
3317 dim_names(3) = "Time"
3318 call register_axis(fileobj, dim_names(3), unlimited)
3319 else
3320 dim_names(3) = "zaxis_1"
3321 dim_names(4) = "Time"
3322
3323 call register_axis(fileobj, dim_names(3), nz)
3324 call register_axis(fileobj, dim_names(4), unlimited)
3325 endif !< if (.not. present(nz))
3326
3327 !< Add the dimension names as variable so that the combiner can work correctly
3328 call register_field(fileobj, dim_names(1), "double", (/dim_names(1)/))
3329 call register_variable_attribute(fileobj, dim_names(1), "axis", "X", str_len=1)
3330
3331 call register_field(fileobj, dim_names(2), "double", (/dim_names(2)/))
3332 call register_variable_attribute(fileobj, dim_names(2), "axis", "Y", str_len=1)
3333
3334 end subroutine register_axis_wrapper_write
3335
3336 subroutine register_axis_wrapper(fileobj, to_read, nz)
3337 type(fmsnetcdfdomainfile_t), intent(inout) :: fileobj !< Domain decomposed fileobj
3338 logical, intent(in) :: to_read !< Flag indicating if reading file
3339 integer, intent(in), optional :: nz !< length of the z dimension
3340
3341 if (to_read) then
3342 call register_axis_wrapper_read(fileobj)
3343 else
3344 call register_axis_wrapper_write(fileobj, nz)
3345 endif
3346
3347 end subroutine register_axis_wrapper
3348
3349 !! @brief Register the fields in a coupler_3d_bc_type to be saved in restart files
3350 !! This subroutine registers the fields in a coupler_2d_bc_type to be saved in restart files
3351 !! specified in the field table.
3352 subroutine ct_register_restarts_3d(var, bc_rest_files, num_rest_files, mpp_domain, to_read, ocean_restart, directory)
3353 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure to be registered for restarts
3354 type(fmsnetcdfdomainfile_t), dimension(:), pointer :: bc_rest_files !< Structures describing the restart files
3355 integer, intent(out) :: num_rest_files !< The number of restart files to use
3356 type(domain2d), intent(in) :: mpp_domain !< The FMS domain to use for this registration call
3357 logical, intent(in) :: to_read !< Flag indicating if reading/writing a file
3358 logical, optional,intent(in) :: ocean_restart !< If true, use the ocean restart file name.
3359 character(len=*),optional,intent(in) :: directory !< Directory where to open the file
3360
3361 character(len=FMS_FILE_LEN), dimension(max(1,var%num_bcs)) :: rest_file_names
3362 character(len=FMS_FILE_LEN) :: file_nm
3363 logical :: ocn_rest
3364 integer :: f, n, m
3365
3366 character(len=20), allocatable, dimension(:) :: dim_names !< Array of dimension names
3367 character(len=20) :: io_type !< flag indicating io type: "read" "overwrite"
3368 logical, dimension(max(1,var%num_bcs)) :: file_is_open !< Flag indicating if file is open
3369 character(len=FMS_PATH_LEN) :: dir !< Directory where to open the file
3370 integer :: nz !< Length of the z direction of each file
3371
3372 if(var%set .and. var%num_bcs .gt. 0) then
3373 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3374 if( associated(var%bc) ) then
3375 call mpp_error(fatal, "CT_register_restarts_3d: var%bc and var%bc_r4 are both intialized,"//&
3376 "only one should be associated per type")
3377 else
3378 call mpp_error(fatal, "CT_register_restarts_3d: var%bc and var%bc_r4 are both unintialized,"//&
3379 "one should be associated per type to register restart fields")
3380 endif
3381 endif
3382 endif
3383
3384 ocn_rest = .true.
3385 if (present(ocean_restart)) ocn_rest = ocean_restart
3386
3387 if (present(directory)) dir = trim(directory)
3388
3389 if (to_read) then
3390 io_type = "read"
3391 if (.not. present(directory)) dir = "INPUT/"
3392 else
3393 io_type = "overwrite"
3394 if (.not. present(directory)) dir = "RESTART/"
3395 endif
3396
3397 nz = var%ke - var%ks + 1 !< NOTE: This assumes that the z dimension is the same for every variable
3398 num_rest_files = 0
3399
3400 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3401 ! Determine the number and names of the restart files
3402 do n = 1, var%num_bcs
3403 if (var%bc(n)%num_fields <= 0) cycle
3404 file_nm = trim(var%bc(n)%ice_restart_file)
3405 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
3406 do f = 1, num_rest_files
3407 if (trim(file_nm) == trim(rest_file_names(f))) exit
3408 enddo
3409 if (f>num_rest_files) then
3410 num_rest_files = num_rest_files + 1
3411 rest_file_names(f) = trim(file_nm)
3412 endif
3413 enddo
3414
3415 if (num_rest_files == 0) return
3416
3417 allocate(bc_rest_files(num_rest_files))
3418
3419 !< Open the files
3420 do n = 1, num_rest_files
3421 file_is_open(n) = open_file(bc_rest_files(n), trim(dir)//rest_file_names(n), io_type, mpp_domain, &
3422 & is_restart=.true.)
3423 if (file_is_open(n)) then
3424
3425 if (to_read) then
3426 call register_axis_wrapper(bc_rest_files(n), to_read=to_read)
3427 else
3428 call register_axis_wrapper(bc_rest_files(n), to_read=to_read, nz=nz)
3429 endif
3430 endif
3431 enddo
3432
3433 ! Register the fields with the restart files
3434 do n = 1, var%num_bcs
3435 if (var%bc(n)%num_fields <= 0) cycle
3436
3437 file_nm = trim(var%bc(n)%ice_restart_file)
3438 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
3439 do f = 1, num_rest_files
3440 if (trim(file_nm) == trim(rest_file_names(f))) exit
3441 enddo
3442
3443 var%bc(n)%fms2_io_rest_type => bc_rest_files(f)
3444
3445 do m = 1, var%bc(n)%num_fields
3446 if (file_is_open(f)) then
3447 if( to_read .and. variable_exists(bc_rest_files(f), var%bc(n)%field(m)%name)) then
3448 !< If reading get the dimension names from the file
3449 allocate(dim_names(get_variable_num_dimensions(bc_rest_files(f), var%bc(n)%field(m)%name)))
3450 call get_variable_dimension_names(bc_rest_files(f), &
3451 & var%bc(n)%field(m)%name, dim_names)
3452 else
3453 !< If writing use dummy dimension names
3454 allocate(dim_names(4))
3455 dim_names(1) = "xaxis_1"
3456 dim_names(2) = "yaxis_1"
3457 dim_names(3) = "zaxis_1"
3458 dim_names(4) = "Time"
3459 endif !< to_read
3460
3461 call register_restart_field(bc_rest_files(f),&
3462 & var%bc(n)%field(m)%name, var%bc(n)%field(m)%values, dim_names, &
3463 & is_optional=var%bc(n)%field(m)%may_init )
3464 deallocate(dim_names)
3465 endif !< If file_is_open
3466 enddo !< num_fields
3467 enddo !< num_bcs
3468 else if(associated(var%bc_r4)) then
3469 ! Determine the number and names of the restart files
3470 do n = 1, var%num_bcs
3471 if (var%bc_r4(n)%num_fields <= 0) cycle
3472 file_nm = trim(var%bc_r4(n)%ice_restart_file)
3473 if (ocn_rest) file_nm = trim(var%bc_r4(n)%ocean_restart_file)
3474 do f = 1, num_rest_files
3475 if (trim(file_nm) == trim(rest_file_names(f))) exit
3476 enddo
3477 if (f>num_rest_files) then
3478 num_rest_files = num_rest_files + 1
3479 rest_file_names(f) = trim(file_nm)
3480 endif
3481 enddo
3482
3483 if (num_rest_files == 0) return
3484
3485 allocate(bc_rest_files(num_rest_files))
3486
3487 !< Open the files
3488 do n = 1, num_rest_files
3489 file_is_open(n) = open_file(bc_rest_files(n), trim(dir)//rest_file_names(n), io_type, mpp_domain, &
3490 & is_restart=.true.)
3491 if (file_is_open(n)) then
3492
3493 if (to_read) then
3494 call register_axis_wrapper(bc_rest_files(n), to_read=to_read)
3495 else
3496 call register_axis_wrapper(bc_rest_files(n), to_read=to_read, nz=nz)
3497 endif
3498 endif
3499 enddo
3500
3501 ! Register the fields with the restart files
3502 do n = 1, var%num_bcs
3503 if (var%bc_r4(n)%num_fields <= 0) cycle
3504
3505 file_nm = trim(var%bc_r4(n)%ice_restart_file)
3506 if (ocn_rest) file_nm = trim(var%bc_r4(n)%ocean_restart_file)
3507 do f = 1, num_rest_files
3508 if (trim(file_nm) == trim(rest_file_names(f))) exit
3509 enddo
3510
3511 var%bc_r4(n)%fms2_io_rest_type => bc_rest_files(f)
3512
3513 do m = 1, var%bc_r4(n)%num_fields
3514 if (file_is_open(f)) then
3515 if( to_read .and. variable_exists(bc_rest_files(f), var%bc_r4(n)%field(m)%name)) then
3516 !< If reading get the dimension names from the file
3517 allocate(dim_names(get_variable_num_dimensions(bc_rest_files(f), var%bc_r4(n)%field(m)%name)))
3518 call get_variable_dimension_names(bc_rest_files(f), &
3519 & var%bc_r4(n)%field(m)%name, dim_names)
3520 else
3521 !< If writing use dummy dimension names
3522 allocate(dim_names(4))
3523 dim_names(1) = "xaxis_1"
3524 dim_names(2) = "yaxis_1"
3525 dim_names(3) = "zaxis_1"
3526 dim_names(4) = "Time"
3527 endif !< to_read
3528
3529 call register_restart_field(bc_rest_files(f),&
3530 & var%bc_r4(n)%field(m)%name, var%bc_r4(n)%field(m)%values, dim_names, &
3531 & is_optional=var%bc_r4(n)%field(m)%may_init )
3532 deallocate(dim_names)
3533 endif !< If file_is_open
3534 enddo !< num_fields
3535 enddo !< num_bcs
3536 else
3537 call mpp_error(fatal, "CT_register_restarts_2d: passed in type has unassociated coupler_field_type"// &
3538 " pointers for both bc and bc_r4")
3539 endif
3540 end subroutine ct_register_restarts_3d
3541
3542 subroutine ct_restore_state_2d(var, use_fms2_io, directory, all_or_nothing, all_required, test_by_field)
3543 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure to restore from restart files
3544 character(len=*), optional, intent(in) :: directory !< A directory where the restart files should
3545 !! be found. The default for FMS is 'INPUT'.
3546 logical, optional, intent(in) :: all_or_nothing !< If true and there are non-mandatory
3547 !! restart fields, it is still an error if some
3548 !! fields are read successfully but others are not.
3549 logical, optional, intent(in) :: all_required !< If true, all fields must be successfully
3550 !! read from the restart file, even if they were
3551 !! registered as not mandatory.
3552 logical, optional, intent(in) :: test_by_field !< If true, all or none of the variables
3553 !! in a single field must be read successfully.
3554 logical, intent(in) :: use_fms2_io !< This is just to distinguish the interfaces
3555
3556 integer :: n, m, num_fld
3557 character(len=80) :: unset_varname
3558 logical :: any_set, all_set, all_var_set, any_var_set, var_set
3559
3560 if(var%set .and. var%num_bcs .gt. 0) then
3561 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3562 if( associated(var%bc) ) then
3563 call mpp_error(fatal, "CT_restore_state_2d: var%bc and var%bc_r4 are both initialized," // &
3564 "only one should be associated per type")
3565 else
3566 call mpp_error(fatal, "CT_restore_state_2d: var%bc and var%bc_r4 are both uninitialized," // &
3567 "one should be associated per type to restore state from restart")
3568 endif
3569 endif
3570 endif
3571
3572 any_set = .false.
3573 all_set = .true.
3574 num_fld = 0
3575 unset_varname = ""
3576
3577 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3578 do n = 1, var%num_bcs
3579 any_var_set = .false.
3580 all_var_set = .true.
3581 do m = 1, var%bc(n)%num_fields
3582 var_set = .false.
3583 if (check_if_open(var%bc(n)%fms2_io_rest_type)) then
3584 var_set = variable_exists(var%bc(n)%fms2_io_rest_type, var%bc(n)%field(m)%name)
3585 endif
3586
3587 if (.not.var_set) unset_varname = trim(var%bc(n)%field(m)%name)
3588 if (var_set) any_set = .true.
3589 if (all_set) all_set = var_set
3590 if (var_set) any_var_set = .true.
3591 if (all_var_set) all_var_set = var_set
3592 enddo
3593
3594 num_fld = num_fld + var%bc(n)%num_fields
3595 if ((var%bc(n)%num_fields > 0) .and. present(test_by_field)) then
3596 if (test_by_field .and. (all_var_set .neqv. any_var_set)) call mpp_error(fatal,&
3597 & "CT_restore_state_2d: test_by_field is true, and "//&
3598 & trim(unset_varname)//" was not read but some other fields in "//&
3599 & trim(trim(var%bc(n)%name))//" were.")
3600 endif
3601 enddo
3602 else if(associated(var%bc_r4)) then
3603 do n = 1, var%num_bcs
3604 any_var_set = .false.
3605 all_var_set = .true.
3606 do m = 1, var%bc_r4(n)%num_fields
3607 var_set = .false.
3608 if (check_if_open(var%bc_r4(n)%fms2_io_rest_type)) then
3609 var_set = variable_exists(var%bc_r4(n)%fms2_io_rest_type, var%bc_r4(n)%field(m)%name)
3610 endif
3611
3612 if (.not.var_set) unset_varname = trim(var%bc_r4(n)%field(m)%name)
3613 if (var_set) any_set = .true.
3614 if (all_set) all_set = var_set
3615 if (var_set) any_var_set = .true.
3616 if (all_var_set) all_var_set = var_set
3617 enddo
3618
3619 num_fld = num_fld + var%bc_r4(n)%num_fields
3620 if ((var%bc_r4(n)%num_fields > 0) .and. present(test_by_field)) then
3621 if (test_by_field .and. (all_var_set .neqv. any_var_set)) call mpp_error(fatal,&
3622 & "CT_restore_state_2d: test_by_field is true, and "//&
3623 & trim(unset_varname)//" was not read but some other fields in "//&
3624 & trim(trim(var%bc_r4(n)%name))//" were.")
3625 endif
3626 enddo
3627 else
3628 call mpp_error(fatal, "CT_restore_state_2d: passed in type has unassociated coupler_field_type"// &
3629 " pointers for both bc and bc_r4")
3630 endif
3631
3632 if ((num_fld > 0) .and. present(all_or_nothing)) then
3633 if (all_or_nothing .and. (all_set .neqv. any_set)) call mpp_error(fatal,&
3634 & "CT_restore_state_2d: all_or_nothing is true, and "//&
3635 & trim(unset_varname)//" was not read but some other fields were.")
3636 endif
3637
3638 if (present(all_required)) then
3639 if (all_required .and. .not.all_set) then
3640 call mpp_error(fatal, "CT_restore_state_2d: all_required is true, but "//&
3641 & trim(unset_varname)//" was not read from its restart file.")
3642 endif
3643 endif
3644 end subroutine ct_restore_state_2d
3645
3646 !> @brief Read in fields from restart files into a coupler_3d_bc_type
3647 !!
3648 !! This subroutine reads in the fields in a coupler_3d_bc_type that have been saved in restart
3649 !! files.
3650 subroutine ct_restore_state_3d(var, use_fms2_io, directory, all_or_nothing, all_required, test_by_field)
3651 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure to restore from restart files
3652 character(len=*), optional, intent(in) :: directory !< A directory where the restart files should
3653 !! be found. The default for FMS is 'INPUT'.
3654 logical, intent(in) :: use_fms2_io !< This is just to distinguish the interfaces
3655 logical, optional, intent(in) :: all_or_nothing !< If true and there are non-mandatory
3656 !! restart fields, it is still an error if some
3657 !! fields are read successfully but others are not.
3658 logical, optional, intent(in) :: all_required !< If true, all fields must be successfully
3659 !! read from the restart file, even if they were
3660 !! registered as not mandatory.
3661 logical, optional, intent(in) :: test_by_field !< If true, all or none of the variables
3662 !! in a single field must be read successfully.
3663
3664 integer :: n, m, num_fld
3665 character(len=80) :: unset_varname
3666 logical :: any_set, all_set, all_var_set, any_var_set, var_set
3667
3668 if(var%set .and. var%num_bcs .gt. 0) then
3669 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3670 if( associated(var%bc) ) then
3671 call mpp_error(fatal, "CT_restore_state_3d: var%bc and var%bc_r4 are both initialized," // &
3672 "only one should be associated per type")
3673 else
3674 call mpp_error(fatal, "CT_restore_state_3d: var%bc and var%bc_r4 are both uninitialized," // &
3675 "one should be associated per type to restore state from restart")
3676 endif
3677 endif
3678 endif
3679
3680 any_set = .false.
3681 all_set = .true.
3682 num_fld = 0
3683 unset_varname = ""
3684
3685 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3686 do n = 1, var%num_bcs
3687 any_var_set = .false.
3688 all_var_set = .true.
3689 do m = 1, var%bc(n)%num_fields
3690 var_set = .false.
3691 if (check_if_open(var%bc(n)%fms2_io_rest_type)) then
3692 var_set = variable_exists(var%bc(n)%fms2_io_rest_type, var%bc(n)%field(m)%name)
3693 endif
3694
3695 if (.not.var_set) unset_varname = trim(var%bc(n)%field(m)%name)
3696
3697 if (var_set) any_set = .true.
3698 if (all_set) all_set = var_set
3699 if (var_set) any_var_set = .true.
3700 if (all_var_set) all_var_set = var_set
3701 enddo
3702
3703 num_fld = num_fld + var%bc(n)%num_fields
3704 if ((var%bc(n)%num_fields > 0) .and. present(test_by_field)) then
3705 if (test_by_field .and. (all_var_set .neqv. any_var_set)) call mpp_error(fatal,&
3706 & "CT_restore_state_3d: test_by_field is true, and "//&
3707 & trim(unset_varname)//" was not read but some other fields in "//&
3708 & trim(trim(var%bc(n)%name))//" were.")
3709 endif
3710 enddo
3711 else if(associated(var%bc_r4)) then
3712 do n = 1, var%num_bcs
3713 any_var_set = .false.
3714 all_var_set = .true.
3715 do m = 1, var%bc_r4(n)%num_fields
3716 var_set = .false.
3717 if (check_if_open(var%bc_r4(n)%fms2_io_rest_type)) then
3718 var_set = variable_exists(var%bc_r4(n)%fms2_io_rest_type, var%bc_r4(n)%field(m)%name)
3719 endif
3720
3721 if (.not.var_set) unset_varname = trim(var%bc_r4(n)%field(m)%name)
3722
3723 if (var_set) any_set = .true.
3724 if (all_set) all_set = var_set
3725 if (var_set) any_var_set = .true.
3726 if (all_var_set) all_var_set = var_set
3727 enddo
3728
3729 num_fld = num_fld + var%bc_r4(n)%num_fields
3730 if ((var%bc_r4(n)%num_fields > 0) .and. present(test_by_field)) then
3731 if (test_by_field .and. (all_var_set .neqv. any_var_set)) call mpp_error(fatal,&
3732 & "CT_restore_state_3d: test_by_field is true, and "//&
3733 & trim(unset_varname)//" was not read but some other fields in "//&
3734 & trim(trim(var%bc(n)%name))//" were.")
3735 endif
3736 enddo
3737 else
3738 call mpp_error(fatal, "CT_restore_state_3d: passed in type has unassociated coupler_field_type"// &
3739 " pointers for both bc and bc_r4")
3740 endif
3741
3742
3743 if ((num_fld > 0) .and. present(all_or_nothing)) then
3744 if (all_or_nothing .and. (all_set .neqv. any_set)) call mpp_error(fatal,&
3745 & "CT_restore_state_3d: all_or_nothing is true, and "//&
3746 & trim(unset_varname)//" was not read but some other fields were.")
3747 endif
3748
3749 if (present(all_required)) then
3750 if (all_required .and. .not.all_set) then
3751 call mpp_error(fatal, "CT_restore_state_3d: all_required is true, but "//&
3752 & trim(unset_varname)//" was not read from its restart file.")
3753 endif
3754 endif
3755 end subroutine ct_restore_state_3d
3756
3757
3758 !> @brief Potentially override the values in a coupler_2d_bc_type
3759 subroutine ct_data_override_2d(gridname, var, Time)
3760 character(len=3), intent(in) :: gridname !< 3-character long model grid ID
3761 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure to override
3762 type(time_type), intent(in) :: time !< The current model time
3763 integer :: m, n
3764
3765 if(var%set .and. var%num_bcs .gt. 0) then
3766 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3767 if( associated(var%bc) ) then
3768 call mpp_error(fatal, "CT_data_override_2d: var%bc and var%bc_r4 are both initialized," // &
3769 "only one should be associated per type")
3770 else
3771 call mpp_error(fatal, "CT_data_override_2d: var%bc and var%bc_r4 are both uninitialized," // &
3772 "one should be associated per type to perform data override")
3773 endif
3774 endif
3775 endif
3776
3777 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3778 do n = 1, var%num_bcs
3779 do m = 1, var%bc(n)%num_fields
3780 call data_override(gridname, var%bc(n)%field(m)%name, var%bc(n)%field(m)%values, time)
3781 enddo
3782 enddo
3783 else if(associated(var%bc_r4)) then
3784 do n = 1, var%num_bcs
3785 do m = 1, var%bc_r4(n)%num_fields
3786 call data_override(gridname, var%bc_r4(n)%field(m)%name, var%bc_r4(n)%field(m)%values, time)
3787 enddo
3788 enddo
3789 else
3790 call mpp_error(fatal, "CT_data_override_2d: passed in type has unassociated coupler_field_type"// &
3791 " pointers for both bc and bc_r4")
3792 endif
3793 end subroutine ct_data_override_2d
3794
3795 !> @brief Potentially override the values in a coupler_3d_bc_type
3796 subroutine ct_data_override_3d(gridname, var, Time)
3797 character(len=3), intent(in) :: gridname !< 3-character long model grid ID
3798 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure to override
3799 type(time_type), intent(in) :: time !< The current model time
3800 !! TODO remove this when data_override is merged in
3801 real(r8_kind), allocatable :: r8_field_values(:,:,:)
3802
3803 integer :: m, n
3804
3805 if(var%set .and. var%num_bcs .gt. 0) then
3806 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3807 if( associated(var%bc) ) then
3808 call mpp_error(fatal, "CT_data_override_3d: var%bc and var%bc_r4 are both initialized," // &
3809 "only one should be associated per type")
3810 else
3811 call mpp_error(fatal, "CT_data_override_3d: var%bc and var%bc_r4 are both uninitialized," // &
3812 "one should be associated per type to perform data override")
3813 endif
3814 endif
3815 endif
3816
3817 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3818 do n = 1, var%num_bcs
3819 do m = 1, var%bc(n)%num_fields
3820 call data_override(gridname, var%bc(n)%field(m)%name, var%bc(n)%field(m)%values, time)
3821 enddo
3822 enddo
3823 else if(associated(var%bc_r4)) then
3824 do n = 1, var%num_bcs
3825 do m = 1, var%bc_r4(n)%num_fields
3826 call data_override(gridname, var%bc_r4(n)%field(m)%name, var%bc_r4(n)%field(m)%values, time)
3827 enddo
3828 enddo
3829 else
3830 call mpp_error(fatal, "CT_data_override_3d: passed in type has unassociated coupler_field_type"// &
3831 " pointers for both bc and bc_r4")
3832 endif
3833
3834 end subroutine ct_data_override_3d
3835
3836
3837 !> @brief Write out checksums for the elements of a coupler_2d_bc_type
3838 subroutine ct_write_chksums_2d(var, outunit, name_lead)
3839 type(coupler_2d_bc_type), intent(in) :: var !< BC_type structure for which to register diagnostics
3840 integer, intent(in) :: outunit !< The index of a open output file
3841 character(len=*), optional, intent(in) :: name_lead !< An optional prefix for the variable names
3842
3843 character(len=120) :: var_name
3844 integer :: m, n
3845 integer(i8_kind) :: chks ! A checksum for the field
3846
3847 if(var%set .and. var%num_bcs .gt. 0) then
3848 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3849 if( associated(var%bc) ) then
3850 call mpp_error(fatal, "CT_write_chksums_2d: var%bc and var%bc_r4 are both initialized," // &
3851 "only one should be associated per type")
3852 else
3853 call mpp_error(fatal, "CT_write_chksums_2d: var%bc and var%bc_r4 are both uninitialized," // &
3854 "one should be associated per type to write checksums for fields")
3855 endif
3856 endif
3857 endif
3858
3859 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3860 do n = 1, var%num_bcs
3861 do m = 1, var%bc(n)%num_fields
3862 if (present(name_lead)) then
3863 var_name = trim(name_lead)//trim(var%bc(n)%field(m)%name)
3864 else
3865 var_name = trim(var%bc(n)%field(m)%name)
3866 endif
3867 chks = mpp_chksum(var%bc(n)%field(m)%values(var%isc:var%iec,var%jsc:var%jec))
3868 if(outunit.ne.0) write(outunit, '(" CHECKSUM:: ",A40," = ",Z20)') trim(var_name), chks
3869 enddo
3870 enddo
3871 else if(associated(var%bc_r4)) then
3872 do n = 1, var%num_bcs
3873 do m = 1, var%bc_r4(n)%num_fields
3874 if (present(name_lead)) then
3875 var_name = trim(name_lead)//trim(var%bc_r4(n)%field(m)%name)
3876 else
3877 var_name = trim(var%bc_r4(n)%field(m)%name)
3878 endif
3879 chks = mpp_chksum(var%bc_r4(n)%field(m)%values(var%isc:var%iec,var%jsc:var%jec))
3880 if(outunit.ne.0) write(outunit, '(" CHECKSUM:: ",A40," = ",Z20)') trim(var_name), chks
3881 enddo
3882 enddo
3883 else
3884 call mpp_error(fatal, "CT_write_chksums_2d: passed in type has unassociated coupler_field_type"// &
3885 " pointers for both bc and bc_r4")
3886 endif
3887 end subroutine ct_write_chksums_2d
3888
3889 !> @brief Write out checksums for the elements of a coupler_3d_bc_type
3890 subroutine ct_write_chksums_3d(var, outunit, name_lead)
3891 type(coupler_3d_bc_type), intent(in) :: var !< BC_type structure for which to register diagnostics
3892 integer, intent(in) :: outunit !< The index of a open output file
3893 character(len=*), optional, intent(in) :: name_lead !< An optional prefix for the variable names
3894
3895 character(len=120) :: var_name
3896 integer :: m, n
3897 integer(i8_kind) :: chks ! A checksum for the field
3898
3899 if(var%set .and. var%num_bcs .gt. 0) then
3900 if(associated(var%bc) .eqv. associated(var%bc_r4)) then
3901 if( associated(var%bc) ) then
3902 call mpp_error(fatal, "CT_write_chksums_3d: var%bc and var%bc_r4 are both initialized," // &
3903 "only one should be associated per type")
3904 else
3905 call mpp_error(fatal, "CT_write_chksums_3d: var%bc and var%bc_r4 are both uninitialized," // &
3906 "one should be associated per type to write checksums for fields")
3907 endif
3908 endif
3909 endif
3910
3911 if(associated(var%bc) .or. var%num_bcs .lt. 1) then
3912 do n = 1, var%num_bcs
3913 do m = 1, var%bc(n)%num_fields
3914 if (present(name_lead)) then
3915 var_name = trim(name_lead)//trim(var%bc(n)%field(m)%name)
3916 else
3917 var_name = trim(var%bc(n)%field(m)%name)
3918 endif
3919 chks = mpp_chksum(var%bc(n)%field(m)%values(var%isc:var%iec,var%jsc:var%jec,:))
3920 if(outunit.ne.0) write(outunit, '(" CHECKSUM:: ",A40," = ",Z20)') trim(var_name), chks
3921 enddo
3922 enddo
3923 else if(associated(var%bc_r4)) then
3924 do n = 1, var%num_bcs
3925 do m = 1, var%bc_r4(n)%num_fields
3926 if (present(name_lead)) then
3927 var_name = trim(name_lead)//trim(var%bc_r4(n)%field(m)%name)
3928 else
3929 var_name = trim(var%bc_r4(n)%field(m)%name)
3930 endif
3931 chks = mpp_chksum(var%bc_r4(n)%field(m)%values(var%isc:var%iec,var%jsc:var%jec,:))
3932 if(outunit.ne.0) write(outunit, '(" CHECKSUM:: ",A40," = ",Z20)') trim(var_name), chks
3933 enddo
3934 enddo
3935 else
3936 call mpp_error(fatal, "CT_write_chksums_2d: passed in type has unassociated coupler_field_type"// &
3937 " pointers for both bc and bc_r4")
3938 endif
3939
3940 end subroutine ct_write_chksums_3d
3941
3942 !> @brief Indicate whether a coupler_1d_bc_type has been initialized.
3943 !! @return Logical
3944 logical function ct_initialized_1d(var)
3945 type(coupler_1d_bc_type), intent(in) :: var !< BC_type structure to check initialization
3946
3947 ct_initialized_1d = var%set
3948 end function ct_initialized_1d
3949
3950 !> @brief Indicate whether a coupler_2d_bc_type has been initialized.
3951 !! @return Logical
3952 logical function ct_initialized_2d(var)
3953 type(coupler_2d_bc_type), intent(in) :: var !< BC_type structure to check initialization
3954
3955 ct_initialized_2d = var%set
3956 end function ct_initialized_2d
3957
3958 !> @brief Indicate whether a coupler_3d_bc_type has been initialized.
3959 !! @return Logical
3960 logical function ct_initialized_3d(var)
3961 type(coupler_3d_bc_type), intent(in) :: var !< BC_type structure to check initialization
3962
3963 ct_initialized_3d = var%set
3964 end function ct_initialized_3d
3965
3966 !> @brief Deallocate all data associated with a coupler_1d_bc_type
3967 subroutine ct_destructor_1d(var)
3968 type(coupler_1d_bc_type), intent(inout) :: var !< BC_type structure to be deconstructed
3969
3970 integer :: m, n
3971
3972 if (var%num_bcs > 0) then
3973 if(associated(var%bc)) then
3974 do n = 1, var%num_bcs
3975 do m = 1, var%bc(n)%num_fields
3976 deallocate ( var%bc(n)%field(m)%values )
3977 enddo
3978 deallocate ( var%bc(n)%field )
3979 enddo
3980 deallocate ( var%bc )
3981 else if(associated(var%bc_r4)) then
3982 do n = 1, var%num_bcs
3983 do m = 1, var%bc_r4(n)%num_fields
3984 deallocate ( var%bc_r4(n)%field(m)%values )
3985 enddo
3986 deallocate ( var%bc_r4(n)%field )
3987 enddo
3988 deallocate ( var%bc_r4 )
3989 else
3990 call mpp_error(fatal, "CT_destructor_1d: passed in type has unassociated coupler_field_type"// &
3991 " pointers for both bc and bc_r4")
3992 endif
3993 endif
3994
3995 var%num_bcs = 0
3996 var%set = .false.
3997 end subroutine ct_destructor_1d
3998
3999 !> @brief Deallocate all data associated with a coupler_2d_bc_type
4000 subroutine ct_destructor_2d(var)
4001 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure to be deconstructed
4002
4003 integer :: m, n
4004
4005 if (var%num_bcs > 0) then
4006 if(associated(var%bc)) then
4007 do n = 1, var%num_bcs
4008 do m = 1, var%bc(n)%num_fields
4009 deallocate ( var%bc(n)%field(m)%values )
4010 enddo
4011 deallocate ( var%bc(n)%field )
4012 enddo
4013 deallocate ( var%bc )
4014 else if(associated(var%bc_r4)) then
4015 do n = 1, var%num_bcs
4016 do m = 1, var%bc_r4(n)%num_fields
4017 deallocate ( var%bc_r4(n)%field(m)%values )
4018 enddo
4019 deallocate ( var%bc_r4(n)%field )
4020 enddo
4021 deallocate ( var%bc_r4 )
4022 else
4023 call mpp_error(fatal, "CT_destructor_2d: passed in type has unassociated coupler_field_type"// &
4024 " pointers for both bc and bc_r4")
4025 endif
4026 endif
4027
4028 var%num_bcs = 0
4029 var%set = .false.
4030 end subroutine ct_destructor_2d
4031
4032 !> @brief Deallocate all data associated with a coupler_3d_bc_type
4033 subroutine ct_destructor_3d(var)
4034 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure to be deconstructed
4035
4036 integer :: m, n
4037
4038 if (var%num_bcs > 0) then
4039 if(associated(var%bc)) then
4040 do n = 1, var%num_bcs
4041 do m = 1, var%bc(n)%num_fields
4042 deallocate ( var%bc(n)%field(m)%values )
4043 enddo
4044 deallocate ( var%bc(n)%field )
4045 enddo
4046 deallocate ( var%bc )
4047 else if(associated(var%bc_r4)) then
4048 do n = 1, var%num_bcs
4049 do m = 1, var%bc_r4(n)%num_fields
4050 deallocate ( var%bc_r4(n)%field(m)%values )
4051 enddo
4052 deallocate ( var%bc_r4(n)%field )
4053 enddo
4054 deallocate ( var%bc_r4 )
4055 else
4056 call mpp_error(fatal, "CT_destructor_3d: passed in type has unassociated coupler_field_type"// &
4057 " pointers for both bc and bc_r4")
4058 endif
4059
4060 endif
4061
4062 var%num_bcs = 0
4063 var%set = .false.
4064 end subroutine ct_destructor_3d
4065
4066#include "coupler_types_r4.fh"
4067#include "coupler_types_r8.fh"
4068
4069 !! @brief Register the fields in a coupler_2d_bc_type to be saved in restart files
4070 !!
4071 !! This subroutine registers the fields in a coupler_2d_bc_type to be saved in restart files
4072 !! specified in the field table.
4073#ifdef use_deprecated_io
4074 subroutine mpp_io_ct_register_restarts_2d(var, bc_rest_files, num_rest_files, mpp_domain, ocean_restart)
4075 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure to be registered for restarts
4076 type(restart_file_type), dimension(:), pointer :: bc_rest_files !< Structures describing the restart files
4077 integer, intent(out) :: num_rest_files !< The number of restart files to use
4078 type(domain2d), intent(in) :: mpp_domain !< The FMS domain to use for this registration call
4079 logical, optional, intent(in) :: ocean_restart !< If true, use the ocean restart file name.
4080
4081 character(len=80), dimension(max(1,var%num_bcs)) :: rest_file_names
4082 character(len=80) :: file_nm
4083 logical :: ocn_rest
4084 integer :: f, n, m
4085
4086 ocn_rest = .true.
4087 if (present(ocean_restart)) ocn_rest = ocean_restart
4088
4089 ! Determine the number and names of the restart files
4090 num_rest_files = 0
4091 do n = 1, var%num_bcs
4092 if (var%bc(n)%num_fields <= 0) cycle
4093 file_nm = trim(var%bc(n)%ice_restart_file)
4094 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
4095 do f = 1, num_rest_files
4096 if (trim(file_nm) == trim(rest_file_names(f))) exit
4097 enddo
4098 if (f>num_rest_files) then
4099 num_rest_files = num_rest_files + 1
4100 rest_file_names(f) = trim(file_nm)
4101 endif
4102 enddo
4103
4104 if (num_rest_files == 0) return
4105
4106 ! Register the fields with the restart files
4107 allocate(bc_rest_files(num_rest_files))
4108 do n = 1, var%num_bcs
4109 if (var%bc(n)%num_fields <= 0) cycle
4110
4111 file_nm = trim(var%bc(n)%ice_restart_file)
4112 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
4113 do f = 1, num_rest_files
4114 if (trim(file_nm) == trim(rest_file_names(f))) exit
4115 enddo
4116
4117 var%bc(n)%rest_type => bc_rest_files(f)
4118 do m = 1, var%bc(n)%num_fields
4119 var%bc(n)%field(m)%id_rest = fms_io_register_restart_field(bc_rest_files(f),&
4120 & rest_file_names(f), var%bc(n)%field(m)%name, var%bc(n)%field(m)%values,&
4121 & mpp_domain, mandatory=.not.var%bc(n)%field(m)%may_init )
4122 enddo
4123 enddo
4124 end subroutine mpp_io_ct_register_restarts_2d
4125
4126 !! @brief Register the fields in a coupler_2d_bc_type to be saved to restart files
4127 !!
4128 !! This subroutine registers the fields in a coupler_2d_bc_type to be saved in the specified
4129 !! restart file.
4130 subroutine mpp_io_ct_register_restarts_to_file_2d(var, file_name, rest_file, mpp_domain, varname_prefix)
4131 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure to be registered for restarts
4132 character(len=*), intent(in) :: file_name !< The name of the restart file
4133 type(restart_file_type), pointer :: rest_file !< A (possibly associated) structure describing
4134 !! the restart file
4135 type(domain2d), intent(in) :: mpp_domain !< The FMS domain to use for this registration call
4136 character(len=*), optional, intent(in) :: varname_prefix !< A prefix for the variable name
4137 !! in the restart file, intended to allow
4138 !! multiple BC_type variables to use the
4139 !! same restart files.
4140
4141 character(len=128) :: var_name
4142 integer :: n, m
4143
4144 ! Register the fields with the restart file
4145 if (.not.associated(rest_file)) allocate(rest_file)
4146 do n = 1, var%num_bcs
4147 if (var%bc(n)%num_fields <= 0) cycle
4148
4149 var%bc(n)%rest_type => rest_file
4150 do m = 1, var%bc(n)%num_fields
4151 var_name = trim(var%bc(n)%field(m)%name)
4152 if (present(varname_prefix)) var_name = trim(varname_prefix)//trim(var_name)
4153 var%bc(n)%field(m)%id_rest = fms_io_register_restart_field(rest_file,&
4154 & file_name, var_name, var%bc(n)%field(m)%values,&
4155 & mpp_domain, mandatory=.not.var%bc(n)%field(m)%may_init )
4156 enddo
4157 enddo
4158 end subroutine mpp_io_ct_register_restarts_to_file_2d
4159
4160 !! @brief Register the fields in a coupler_3d_bc_type to be saved to restart files
4161 !!
4162 !! This subroutine registers the fields in a coupler_3d_bc_type to be saved in restart files
4163 !! specified in the field table.
4164 subroutine mpp_io_ct_register_restarts_3d(var, bc_rest_files, num_rest_files, mpp_domain, ocean_restart)
4165 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure to be registered for restarts
4166 type(restart_file_type), dimension(:), pointer :: bc_rest_files !< Structures describing the restart files
4167 integer, intent(out) :: num_rest_files !< The number of restart files to use
4168 type(domain2d), intent(in) :: mpp_domain !< The FMS domain to use for this registration call
4169 logical, optional, intent(in) :: ocean_restart !< If true, use the ocean restart file name.
4170
4171 character(len=80), dimension(max(1,var%num_bcs)) :: rest_file_names
4172 character(len=80) :: file_nm
4173 logical :: ocn_rest
4174 integer :: f, n, m
4175
4176 ocn_rest = .true.
4177 if (present(ocean_restart)) ocn_rest = ocean_restart
4178
4179 ! Determine the number and names of the restart files
4180 num_rest_files = 0
4181 do n = 1, var%num_bcs
4182 if (var%bc(n)%num_fields <= 0) cycle
4183 file_nm = trim(var%bc(n)%ice_restart_file)
4184 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
4185 do f = 1, num_rest_files
4186 if (trim(file_nm) == trim(rest_file_names(f))) exit
4187 enddo
4188 if (f>num_rest_files) then
4189 num_rest_files = num_rest_files + 1
4190 rest_file_names(f) = trim(file_nm)
4191 endif
4192 enddo
4193
4194 if (num_rest_files == 0) return
4195
4196 ! Register the fields with the restart files
4197 allocate(bc_rest_files(num_rest_files))
4198 do n = 1, var%num_bcs
4199 if (var%bc(n)%num_fields <= 0) cycle
4200 file_nm = trim(var%bc(n)%ice_restart_file)
4201 if (ocn_rest) file_nm = trim(var%bc(n)%ocean_restart_file)
4202 do f = 1, num_rest_files
4203 if (trim(file_nm) == trim(rest_file_names(f))) exit
4204 enddo
4205
4206 var%bc(n)%rest_type => bc_rest_files(f)
4207 do m = 1, var%bc(n)%num_fields
4208 var%bc(n)%field(m)%id_rest = fms_io_register_restart_field(bc_rest_files(f),&
4209 & rest_file_names(f), var%bc(n)%field(m)%name, var%bc(n)%field(m)%values,&
4210 & mpp_domain, mandatory=.not.var%bc(n)%field(m)%may_init )
4211 enddo
4212 enddo
4213 end subroutine mpp_io_ct_register_restarts_3d
4214
4215 !> @brief Register the fields in a coupler_3d_bc_type to be saved to restart files
4216 !!
4217 !! Registers the fields in a coupler_3d_bc_type to be saved in the specified restart file.
4218 subroutine mpp_io_ct_register_restarts_to_file_3d(var, file_name, rest_file, mpp_domain, varname_prefix)
4219 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure to be registered for restarts
4220 character(len=*), intent(in) :: file_name !< The name of the restart file
4221 type(restart_file_type), pointer :: rest_file !< A (possibly associated) structure describing the restart file
4222 type(domain2d), intent(in) :: mpp_domain !< The FMS domain to use for this registration call
4223 character(len=*), optional, intent(in) :: varname_prefix !< A prefix for the variable name
4224 !! in the restart file, intended to allow
4225 !! multiple BC_type variables to use the
4226 !! same restart files.
4227
4228 character(len=128) :: var_name
4229 integer :: n, m
4230
4231 ! Register the fields with the restart file
4232 if (.not.associated(rest_file)) allocate(rest_file)
4233 do n = 1, var%num_bcs
4234 if (var%bc(n)%num_fields <= 0) cycle
4235
4236 var%bc(n)%rest_type => rest_file
4237 do m = 1, var%bc(n)%num_fields
4238 var_name = trim(var%bc(n)%field(m)%name)
4239 if (present(varname_prefix)) var_name = trim(varname_prefix)//trim(var_name)
4240 var%bc(n)%field(m)%id_rest = fms_io_register_restart_field(rest_file,&
4241 & file_name, var_name, var%bc(n)%field(m)%values,&
4242 & mpp_domain, mandatory=.not.var%bc(n)%field(m)%may_init )
4243 enddo
4244 enddo
4245 end subroutine mpp_io_ct_register_restarts_to_file_3d
4246
4247 !> @brief Reads in fields from restart files into a coupler_2d_bc_type
4248 !!
4249 !! This subroutine reads in the fields in a coupler_2d_bc_type that have been saved in restart
4250 !! files.
4251 subroutine mpp_io_ct_restore_state_2d(var, directory, all_or_nothing, all_required, test_by_field)
4252 type(coupler_2d_bc_type), intent(inout) :: var !< BC_type structure to restore from restart files
4253 character(len=*), optional, intent(in) :: directory !< A directory where the restart files should
4254 !! be found. The default for FMS is 'INPUT'.
4255 logical, optional, intent(in) :: all_or_nothing !< If true and there are non-mandatory
4256 !! restart fields, it is still an error if some
4257 !! fields are read successfully but others are not.
4258 logical, optional, intent(in) :: all_required !< If true, all fields must be successfully
4259 !! read from the restart file, even if they were
4260 !! registered as not mandatory.
4261 logical, optional, intent(in) :: test_by_field !< If true, all or none of the variables
4262 !! in a single field must be read successfully.
4263
4264 integer :: n, m, num_fld
4265 character(len=80) :: unset_varname
4266 logical :: any_set, all_set, all_var_set, any_var_set, var_set
4267
4268 any_set = .false.
4269 all_set = .true.
4270 num_fld = 0
4271 unset_varname = ""
4272
4273 do n = 1, var%num_bcs
4274 any_var_set = .false.
4275 all_var_set = .true.
4276 do m = 1, var%bc(n)%num_fields
4277 var_set = .false.
4278 if (var%bc(n)%field(m)%id_rest > 0) then
4279 var_set = query_initialized(var%bc(n)%rest_type, var%bc(n)%field(m)%id_rest)
4280 if (.not.var_set) then
4281 call restore_state(var%bc(n)%rest_type, var%bc(n)%field(m)%id_rest,&
4282 & directory=directory, nonfatal_missing_files=.true.)
4283 var_set = query_initialized(var%bc(n)%rest_type, var%bc(n)%field(m)%id_rest)
4284 endif
4285 endif
4286
4287 if (.not.var_set) unset_varname = trim(var%bc(n)%field(m)%name)
4288 if (var_set) any_set = .true.
4289 if (all_set) all_set = var_set
4290 if (var_set) any_var_set = .true.
4291 if (all_var_set) all_var_set = var_set
4292 enddo
4293
4294 num_fld = num_fld + var%bc(n)%num_fields
4295 if ((var%bc(n)%num_fields > 0) .and. present(test_by_field)) then
4296 if (test_by_field .and. (all_var_set .neqv. any_var_set)) call mpp_error(fatal,&
4297 & "mpp_io_CT_restore_state_2d: test_by_field is true, and "//&
4298 & trim(unset_varname)//" was not read but some other fields in "//&
4299 & trim(trim(var%bc(n)%name))//" were.")
4300 endif
4301 enddo
4302
4303 if ((num_fld > 0) .and. present(all_or_nothing)) then
4304 if (all_or_nothing .and. (all_set .neqv. any_set)) call mpp_error(fatal,&
4305 & "mpp_io_CT_restore_state_2d: all_or_nothing is true, and "//&
4306 & trim(unset_varname)//" was not read but some other fields were.")
4307 endif
4308
4309 if (present(all_required)) then
4310 if (all_required .and. .not.all_set) then
4311 call mpp_error(fatal, "mpp_io_CT_restore_state_2d: all_required is true, but "//&
4312 & trim(unset_varname)//" was not read from its restart file.")
4313 endif
4314 endif
4315 end subroutine mpp_io_ct_restore_state_2d
4316
4317 !> @brief Read in fields from restart files into a coupler_3d_bc_type
4318 !!
4319 !! This subroutine reads in the fields in a coupler_3d_bc_type that have been saved in restart
4320 !! files.
4321 subroutine mpp_io_ct_restore_state_3d(var, directory, all_or_nothing, all_required, test_by_field)
4322 type(coupler_3d_bc_type), intent(inout) :: var !< BC_type structure to restore from restart files
4323 character(len=*), optional, intent(in) :: directory !< A directory where the restart files should
4324 !! be found. The default for FMS is 'INPUT'.
4325 logical, optional, intent(in) :: all_or_nothing !< If true and there are non-mandatory
4326 !! restart fields, it is still an error if some
4327 !! fields are read successfully but others are not.
4328 logical, optional, intent(in) :: all_required !< If true, all fields must be successfully
4329 !! read from the restart file, even if they were
4330 !! registered as not mandatory.
4331 logical, optional, intent(in) :: test_by_field !< If true, all or none of the variables
4332 !! in a single field must be read successfully.
4333
4334 integer :: n, m, num_fld
4335 character(len=80) :: unset_varname
4336 logical :: any_set, all_set, all_var_set, any_var_set, var_set
4337
4338 any_set = .false.
4339 all_set = .true.
4340 num_fld = 0
4341 unset_varname = ""
4342
4343 do n = 1, var%num_bcs
4344 any_var_set = .false.
4345 all_var_set = .true.
4346 do m = 1, var%bc(n)%num_fields
4347 var_set = .false.
4348 if (var%bc(n)%field(m)%id_rest > 0) then
4349 var_set = query_initialized(var%bc(n)%rest_type, var%bc(n)%field(m)%id_rest)
4350 if (.not.var_set) then
4351 call restore_state(var%bc(n)%rest_type, var%bc(n)%field(m)%id_rest,&
4352 & directory=directory, nonfatal_missing_files=.true.)
4353 var_set = query_initialized(var%bc(n)%rest_type, var%bc(n)%field(m)%id_rest)
4354 endif
4355 endif
4356
4357 if (.not.var_set) unset_varname = trim(var%bc(n)%field(m)%name)
4358
4359 if (var_set) any_set = .true.
4360 if (all_set) all_set = var_set
4361 if (var_set) any_var_set = .true.
4362 if (all_var_set) all_var_set = var_set
4363 enddo
4364
4365 num_fld = num_fld + var%bc(n)%num_fields
4366 if ((var%bc(n)%num_fields > 0) .and. present(test_by_field)) then
4367 if (test_by_field .and. (all_var_set .neqv. any_var_set)) call mpp_error(fatal,&
4368 & "mpp_io_CT_restore_state_3d: test_by_field is true, and "//&
4369 & trim(unset_varname)//" was not read but some other fields in "//&
4370 & trim(trim(var%bc(n)%name))//" were.")
4371 endif
4372 enddo
4373
4374 if ((num_fld > 0) .and. present(all_or_nothing)) then
4375 if (all_or_nothing .and. (all_set .neqv. any_set)) call mpp_error(fatal,&
4376 & "mpp_io_CT_restore_state_3d: all_or_nothing is true, and "//&
4377 & trim(unset_varname)//" was not read but some other fields were.")
4378 endif
4379
4380 if (present(all_required)) then
4381 if (all_required .and. .not.all_set) then
4382 call mpp_error(fatal, "mpp_io_CT_restore_state_3d: all_required is true, but "//&
4383 & trim(unset_varname)//" was not read from its restart file.")
4384 endif
4385 endif
4386 end subroutine mpp_io_ct_restore_state_3d
4387#endif
4388end module coupler_types_mod
4389!> @}
4390! close documentation grouping
subroutine ct_spawn_3d_2d(var_in, var, idim, jdim, suffix, as_needed)
Generate one coupler type using another as a template. 3-D to 2-D version for generic CT_spawn.
integer, public ind_kw
The index for the piston velocity.
subroutine register_axis_wrapper_read(fileobj)
integer, public ind_u10
The index of the 10 m wind speed.
subroutine ct_destructor_1d(var)
Deallocate all data associated with a coupler_1d_bc_type.
subroutine coupler_type_copy_2d_2d(var_in, var_out, is, ie, js, je, diag_name, axes, time, suffix)
Copy fields from one coupler type to another. 2-D to 2-D version for generic coupler_type_copy.
subroutine ct_set_diags_2d(var, diag_name, axes, time)
subroutine ct_spawn_1d_3d(var_in, var, idim, jdim, kdim, suffix, as_needed)
Generate one coupler type using another as a template. 1-D to 3-D version for generic CT_spawn.
subroutine ct_copy_data_3d(var_in, var, halo_size, bc_index, field_index, exclude_flux_type, only_flux_type, pass_through_ice)
Copy all elements of coupler_3d_bc_type.
integer, public ind_runoff
The index for a runoff flux.
logical function ct_initialized_3d(var)
Indicate whether a coupler_3d_bc_type has been initialized.
integer, public ind_csurf
The index of the ocean surface concentration.
subroutine, public coupler_types_init
Initialize the coupler types.
subroutine ct_redistribute_data_3d(var_in, domain_in, var_out, domain_out, complete)
Redistributes the data in all elements of one coupler_2d_bc_type.
integer, public ind_sc_no
The index for the Schmidt number for a tracer flux.
subroutine, public coupler_type_copy_1d_3d(var_in, var_out, is, ie, js, je, kd, diag_name, axes, time, suffix)
Copy fields from one coupler type to another. 1-D to 3-D version for generic coupler_type_copy.
integer, public ind_deposition
The index for the atmospheric deposition flux.
subroutine ct_write_chksums_3d(var, outunit, name_lead)
Write out checksums for the elements of a coupler_3d_bc_type.
subroutine ct_spawn_3d_3d(var_in, var, idim, jdim, kdim, suffix, as_needed)
Generate one coupler type using another as a template. 3-D to 3-D version for generic CT_spawn.
subroutine ct_data_override_2d(gridname, var, time)
Potentially override the values in a coupler_2d_bc_type.
subroutine ct_restore_state_2d(var, use_fms2_io, directory, all_or_nothing, all_required, test_by_field)
subroutine ct_data_override_3d(gridname, var, time)
Potentially override the values in a coupler_3d_bc_type.
subroutine ct_spawn_2d_2d(var_in, var, idim, jdim, suffix, as_needed)
Generate one coupler type using another as a template. 2-D to 2-D version for generic CT_spawn.
logical function ct_initialized_2d(var)
Indicate whether a coupler_2d_bc_type has been initialized.
subroutine ct_destructor_2d(var)
Deallocate all data associated with a coupler_2d_bc_type.
subroutine ct_register_restarts_2d(var, bc_rest_files, num_rest_files, mpp_domain, to_read, ocean_restart, directory)
subroutine ct_set_diags_3d(var, diag_name, axes, time)
Register the diagnostics of a coupler_3d_bc_type.
subroutine ct_spawn_1d_2d(var_in, var, idim, jdim, suffix, as_needed)
Generate one coupler type using another as a template. 1-D to 2-D version for generic coupler_type_sp...
integer, public ind_alpha
The index of the solubility array for a tracer.
subroutine ct_spawn_2d_3d(var_in, var, idim, jdim, kdim, suffix, as_needed)
Generate one coupler type using another as a template. 2-D to 3-D version for generic CT_spawn.
subroutine ct_redistribute_data_2d(var_in, domain_in, var_out, domain_out, complete)
Redistribute the data in all elements of a coupler_2d_bc_type.
logical function ct_initialized_1d(var)
Indicate whether a coupler_1d_bc_type has been initialized.
subroutine register_axis_wrapper(fileobj, to_read, nz)
subroutine ct_write_chksums_2d(var, outunit, name_lead)
Write out checksums for the elements of a coupler_2d_bc_type.
subroutine ct_send_data_3d(var, time, return_statuses)
Write out all diagnostics of elements of a coupler_3d_bc_type.
integer, public ind_flux
The index for the tracer flux.
subroutine coupler_type_copy_3d_2d(var_in, var_out, is, ie, js, je, diag_name, axes, time, suffix)
Copy fields from one coupler type to another. 3-D to 2-D version for generic coupler_type_copy.
subroutine ct_increment_data_3d_3d(var_in, var, halo_size, bc_index, field_index, scale_factor, scale_prev, exclude_flux_type, only_flux_type, pass_through_ice)
Increment data in all elements of one coupler_3d_bc_type.
integer, public ind_pcair
The index of the atmospheric concentration.
subroutine ct_copy_data_2d_3d(var_in, var, halo_size, bc_index, field_index, exclude_flux_type, only_flux_type, pass_through_ice, ind3_start, ind3_end)
Copy all elements of coupler_2d_bc_type to coupler_3d_bc_type.
subroutine register_axis_wrapper_write(fileobj, nz)
integer, public ind_flux0
The index for the piston velocity.
subroutine ct_copy_data_2d(var_in, var, halo_size, bc_index, field_index, exclude_flux_type, only_flux_type, pass_through_ice)
Copy all elements of coupler_2d_bc_type. Do a direct copy of the data in all elements of one coupler_...
integer, public ind_psurf
The index of the surface atmospheric pressure.
subroutine ct_destructor_3d(var)
Deallocate all data associated with a coupler_3d_bc_type.
subroutine coupler_type_copy_2d_3d(var_in, var_out, is, ie, js, je, kd, diag_name, axes, time, suffix)
Copy fields from one coupler type to another. 2-D to 3-D version for generic coupler_type_copy.
subroutine coupler_type_copy_3d_3d(var_in, var_out, is, ie, js, je, kd, diag_name, axes, time, suffix)
Copy fields from one coupler type to another. 3-D to 3-D version for generic coupler_type_copy.
subroutine ct_increment_data_2d_2d(var_in, var, halo_size, bc_index, field_index, scale_factor, scale_prev, exclude_flux_type, only_flux_type, pass_through_ice)
Increment data in all elements of one coupler_2d_bc_type.
subroutine ct_send_data_2d(var, time, return_statuses)
Write out all diagnostics of elements of a coupler_2d_bc_type.
integer, public ind_deltap
The index for ocean-air gas partial pressure change.
subroutine, public coupler_type_copy_1d_2d(var_in, var_out, is, ie, js, je, diag_name, axes, time, suffix)
Copy fields from one coupler type to another. 1-D to 2-D version for generic coupler_type_copy.
subroutine ct_restore_state_3d(var, use_fms2_io, directory, all_or_nothing, all_required, test_by_field)
Read in fields from restart files into a coupler_3d_bc_type.
subroutine ct_register_restarts_3d(var, bc_rest_files, num_rest_files, mpp_domain, to_read, ocean_restart, directory)
This is the interface to spawn one coupler_bc_type into another and then register diagnostics associa...
This is the interface to copy the field data from one coupler_bc_type to another of the same rank,...
This is the interface to override the values of the arrays in a coupler_bc_type.
This is the interface to deallocate any data associated with a coupler_bc_type.
This is the interface to extract a field in a coupler_bc_type into an array.
This is the interface to increment the field data from one coupler_bc_type with the data from another...
This function interface indicates whether a coupler_bc_type has been initialized.
This is the interface to redistribute the field data from one coupler_bc_type to another of the same ...
This is the interface to register the fields in a coupler_bc_type to be saved in restart files.
This is the interface to rescale the field data in a coupler_bc_type.
This is the interface to read in the fields in a coupler_bc_type that have been saved in restart file...
This is the interface to write out diagnostics of the arrays in a coupler_bc_type.
This is the interface to set a field in a coupler_bc_type from an array.
This is the interface to set diagnostics for the arrays in a coupler_bc_type.
This is the interface to spawn one coupler_bc_type into another.
This is the interface to write out checksums for the elements of a coupler_bc_type.
Coupler data for 1D boundary conditions.
Coupler data for 2D boundary conditions.
Coupler data for 3D boundary conditions.
Interface for inserting and interpolating data into a file for a model's grid and time....
Register a diagnostic field for a given module.
Send data over to output fields.
Opens a given netcdf or domain file.
Definition fms2_io.F90:122
Add a dimension to a given file.
Definition fms2_io.F90:190
Defines a new field within the given file Example usage:
Definition fms2_io.F90:212
Similar to register_field, but occupies the field with data for restarts Example usage:
Definition fms2_io.F90:231
character(:) function, allocatable, public string(v, fmt)
Converts a number or a Boolean value to a string.
Reorganization of distributed global arrays. mpp_redistribute is used to reorganize a distributed ar...
The domain2D type contains all the necessary information to define the global, compute and data domai...
Calculate parallel checksums.
Definition mpp.F90:1200
Error handler.
Definition mpp.F90:382
Type to represent amounts of time. Implemented as seconds and days to allow for larger intervals.