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