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