← back to index

src/framework/MOM_dyn_horgrid.F90

portedportable, not yet portedexecuted, not portableexecutable, not hit by this run

1! This file is part of MOM6, the Modular Ocean Model version 6.
2! See the LICENSE file for licensing information.
3! SPDX-License-Identifier: Apache-2.0
4
5!> Contains a shareable dynamic type for describing horizontal grids and metric data
6!! and utilty routines that work on this type.
7module MOM_dyn_horgrid
8
9use MOM_array_transform, only : rotate_array, rotate_array_pair
10use MOM_domains, only : MOM_domain_type, deallocate_MOM_domain
11use MOM_error_handler, only : MOM_error, MOM_mesg, FATAL, WARNING
12use MOM_hor_index, only : hor_index_type
13use MOM_unit_scaling, only : unit_scale_type
14
15implicit none ; private
16
17public create_dyn_horgrid, destroy_dyn_horgrid, set_derived_dyn_horgrid
18public rescale_dyn_horgrid_bathymetry, rotate_dyn_horgrid
19
20! A note on unit descriptions in comments: MOM6 uses units that can be rescaled for dimensional
21! consistency testing. These are noted in comments with units like Z, H, L, and T, along with
22! their mks counterparts with notation like "a velocity [Z T-1 ~> m s-1]". If the units
23! vary with the Boussinesq approximation, the Boussinesq variant is given first.
24
25!> Describes the horizontal ocean grid with only dynamic memory arrays
26type, public :: dyn_horgrid_type
27 type(MOM_domain_type), pointer :: Domain => NULL() !< Ocean model domain
28 type(MOM_domain_type), pointer :: Domain_aux => NULL() !< A non-symmetric auxiliary domain type.
29 type(hor_index_type) :: HI !< Horizontal index ranges
30
31 integer :: isc !< The start i-index of cell centers within the computational domain
32 integer :: iec !< The end i-index of cell centers within the computational domain
33 integer :: jsc !< The start j-index of cell centers within the computational domain
34 integer :: jec !< The end j-index of cell centers within the computational domain
35
36 integer :: isd !< The start i-index of cell centers within the data domain
37 integer :: ied !< The end i-index of cell centers within the data domain
38 integer :: jsd !< The start j-index of cell centers within the data domain
39 integer :: jed !< The end j-index of cell centers within the data domain
40
41 integer :: isg !< The start i-index of cell centers within the global domain
42 integer :: ieg !< The end i-index of cell centers within the global domain
43 integer :: jsg !< The start j-index of cell centers within the global domain
44 integer :: jeg !< The end j-index of cell centers within the global domain
45
46 integer :: IscB !< The start i-index of cell vertices within the computational domain
47 integer :: IecB !< The end i-index of cell vertices within the computational domain
48 integer :: JscB !< The start j-index of cell vertices within the computational domain
49 integer :: JecB !< The end j-index of cell vertices within the computational domain
50
51 integer :: IsdB !< The start i-index of cell vertices within the data domain
52 integer :: IedB !< The end i-index of cell vertices within the data domain
53 integer :: JsdB !< The start j-index of cell vertices within the data domain
54 integer :: JedB !< The end j-index of cell vertices within the data domain
55
56 integer :: IsgB !< The start i-index of cell vertices within the global domain
57 integer :: IegB !< The end i-index of cell vertices within the global domain
58 integer :: JsgB !< The start j-index of cell vertices within the global domain
59 integer :: JegB !< The end j-index of cell vertices within the global domain
60
61 integer :: isd_global !< The value of isd in the global index space (decompoistion invariant).
62 integer :: jsd_global !< The value of isd in the global index space (decompoistion invariant).
63 integer :: idg_offset !< The offset between the corresponding global and local i-indices.
64 integer :: jdg_offset !< The offset between the corresponding global and local j-indices.
65 logical :: symmetric !< True if symmetric memory is used.
66
67 logical :: nonblocking_updates !< If true, non-blocking halo updates are
68 !! allowed. The default is .false. (for now).
69 integer :: first_direction !< An integer that indicates which direction is to be updated first in
70 !! directionally split parts of the calculation. This can be altered
71 !! during the course of the run via calls to set_first_direction.
72
73 real, allocatable, dimension(:,:) :: &
74 mask2dT, & !< 0 for land points and 1 for ocean points on the h-grid [nondim].
75 geoLatT, & !< The geographic latitude at q points [degrees of latitude] or [m].
76 geoLonT, & !< The geographic longitude at q points [degrees of longitude] or [m].
77 dxT, & !< dxT is delta x at h points [L ~> m].
78 IdxT, & !< 1/dxT [L-1 ~> m-1].
79 dyT, & !< dyT is delta y at h points [L ~> m].
80 IdyT, & !< IdyT is 1/dyT [L-1 ~> m-1].
81 areaT, & !< The area of an h-cell [L2 ~> m2].
82 IareaT !< 1/areaT [L-2 ~> m-2].
83 real, allocatable, dimension(:,:) :: sin_rot
84 !< The sine of the angular rotation between the local model grid's northward
85 !! and the true northward directions [nondim].
86 real, allocatable, dimension(:,:) :: cos_rot
87 !< The cosine of the angular rotation between the local model grid's northward
88 !! and the true northward directions [nondim].
89
90 real, allocatable, dimension(:,:) :: &
91 mask2dCu, & !< 0 for boundary points and 1 for ocean points on the u grid [nondim].
92 OBCmaskCu, & !< 0 for boundary or OBC points and 1 for ocean points on the u grid [nondim].
93 geoLatCu, & !< The geographic latitude at u points [degrees of latitude] or [m].
94 geoLonCu, & !< The geographic longitude at u points [degrees of longitude] or [m].
95 dxCu, & !< dxCu is delta x at u points [L ~> m].
96 IdxCu, & !< 1/dxCu [L-1 ~> m-1].
97 IdxCu_OBCmask, & !< 1/dxCu or 0 at boundary or OBC points [L-1 ~> m-1].
98 dyCu, & !< dyCu is delta y at u points [L ~> m].
99 IdyCu, & !< 1/dyCu [L-1 ~> m-1].
100 dy_Cu, & !< The unblocked lengths of the u-faces of the h-cell [L ~> m].
101 IareaCu, & !< The masked inverse areas of u-grid cells [L-2 ~> m-2].
102 areaCu !< The areas of the u-grid cells [L2 ~> m2].
103
104 real, allocatable, dimension(:,:) :: &
105 mask2dCv, & !< 0 for boundary points and 1 for ocean points on the v grid [nondim].
106 OBCmaskCv, & !< 0 for boundary or OBC points and 1 for ocean points on the v grid [nondim].
107 geoLatCv, & !< The geographic latitude at v points [degrees of latitude] or [m].
108 geoLonCv, & !< The geographic longitude at v points [degrees of longitude] or [m].
109 dxCv, & !< dxCv is delta x at v points [L ~> m].
110 IdxCv, & !< 1/dxCv [L-1 ~> m-1].
111 dyCv, & !< dyCv is delta y at v points [L ~> m].
112 IdyCv, & !< 1/dyCv [L-1 ~> m-1].
113 IdyCv_OBCmask, & !< 1/dxCv or 0 at boundary or OBC points [L-1 ~> m-1].
114 dx_Cv, & !< The unblocked lengths of the v-faces of the h-cell [L ~> m].
115 IareaCv, & !< The masked inverse areas of v-grid cells [L-2 ~> m-2].
116 areaCv !< The areas of the v-grid cells [L2 ~> m2].
117
118 real, allocatable, dimension(:,:) :: &
119 porous_DminU, & !< minimum topographic height (deepest) of U-face [Z ~> m]
120 porous_DmaxU, & !< maximum topographic height (shallowest) of U-face [Z ~> m]
121 porous_DavgU !< average topographic height of U-face [Z ~> m]
122
123 real, allocatable, dimension(:,:) :: &
124 porous_DminV, & !< minimum topographic height (deepest) of V-face [Z ~> m]
125 porous_DmaxV, & !< maximum topographic height (shallowest) of V-face [Z ~> m]
126 porous_DavgV !< average topographic height of V-face [Z ~> m]
127
128 real, allocatable, dimension(:,:) :: &
129 mask2dBu, & !< 0 for boundary points and 1 for ocean points on the q grid [nondim].
130 geoLatBu, & !< The geographic latitude at q points [degrees of latitude] or [m].
131 geoLonBu, & !< The geographic longitude at q points [degrees of longitude] or [m].
132 dxBu, & !< dxBu is delta x at q points [L ~> m].
133 IdxBu, & !< 1/dxBu [L-1 ~> m-1].
134 dyBu, & !< dyBu is delta y at q points [L ~> m].
135 IdyBu, & !< 1/dyBu [L-1 ~> m-1].
136 areaBu, & !< areaBu is the area of a q-cell [L ~> m]
137 IareaBu !< IareaBu = 1/areaBu [L-2 ~> m-2].
138
139 real, pointer, dimension(:) :: gridLatT => NULL()
140 !< The latitude of T points for the purpose of labeling the output axes,
141 !! often in units of [degrees_N] or [km] or [m] or [gridpoints].
142 !! On many grids this is the same as geoLatT.
143 real, pointer, dimension(:) :: gridLatB => NULL()
144 !< The latitude of B points for the purpose of labeling the output axes,
145 !! often in units of [degrees_N] or [km] or [m] or [gridpoints].
146 !! On many grids this is the same as geoLatBu.
147 real, pointer, dimension(:) :: gridLonT => NULL()
148 !< The longitude of T points for the purpose of labeling the output axes,
149 !! often in units of [degrees_E] or [km] or [m] or [gridpoints].
150 !! On many grids this is the same as geoLonT.
151 real, pointer, dimension(:) :: gridLonB => NULL()
152 !< The longitude of B points for the purpose of labeling the output axes,
153 !! often in units of [degrees_E] or [km] or [m] or [gridpoints].
154 !! On many grids this is the same as geoLonBu.
155 character(len=40) :: &
156 ! Except on a Cartesian grid, these are usually some variant of "degrees".
157 x_axis_units, & !< The units that are used in labeling the x coordinate axes.
158 y_axis_units, & !< The units that are used in labeling the y coordinate axes.
159 ! These are internally generated names, including "m", "km", "deg_E" and "deg_N".
160 x_ax_unit_short, & !< A short description of the x-axis units for documenting parameter units
161 y_ax_unit_short !< A short description of the y-axis units for documenting parameter units
162
163 real, allocatable, dimension(:,:) :: &
164 bathyT !< Ocean bottom depth, referenced to a zero reference height at tracer points.
165 !! bathyT is in depth units and positive *below* the reference height [Z ~> m].
166 real, allocatable, dimension(:,:) :: &
167 meanSL !< Spatially varying time mean sea level, referenced to a zero reference height
168 !! at tracer points. meanSL is in height units and positive *above* zero. It is used
169 !! a) as the height where p = p_atm or zero;
170 !! b) to calculate time mean thickness of the water column, where
171 !! mean thickness = max(meanSL + bathyT, 0.0).
172 !! meanSL is 2D for the consideration of a domain with spatically varying mean
173 !! height, e.g. the Great Lakes system [Z ~> m].
174
175 logical :: bathymetry_at_vel !< If true, there are separate values for the
176 !! basin depths at velocity points. Otherwise the effects of
177 !! of topography are entirely determined from thickness points.
178 real, allocatable, dimension(:,:) :: &
179 Dblock_u, & !< Topographic depths at u-points at which the flow is blocked [Z ~> m].
180 Dopen_u !< Topographic depths at u-points at which the flow is open at width dy_Cu [Z ~> m].
181 real, allocatable, dimension(:,:) :: &
182 Dblock_v, & !< Topographic depths at v-points at which the flow is blocked [Z ~> m].
183 Dopen_v !< Topographic depths at v-points at which the flow is open at width dx_Cv [Z ~> m].
184 real, allocatable, dimension(:,:) :: &
185 CoriolisBu, & !< The Coriolis parameter at corner points [T-1 ~> s-1].
186 Coriolis2Bu !< The square of the Coriolis parameter at corner points [T-2 ~> s-2].
187 real, allocatable, dimension(:,:) :: &
188 df_dx, & !< Derivative d/dx f (Coriolis parameter) at h-points [T-1 L-1 ~> s-1 m-1].
189 df_dy !< Derivative d/dy f (Coriolis parameter) at h-points [T-1 L-1 ~> s-1 m-1].
190
191 ! These variables are global sums that are useful for 1-d diagnostics.
192 real :: areaT_global !< Global sum of h-cell area [L2 ~> m2]
193 real :: IareaT_global !< Global sum of inverse h-cell area (1/areaT_global) [L-2 ~> m-2]
194
195 ! These parameters are run-time parameters that are used during some
196 ! initialization routines (but not all)
197 real :: grid_unit_to_L !< A factor that converts a the geoLat and geoLon variables and related
198 !! variables like len_lat and len_lon into rescaled horizontal distance
199 !! units on a Cartesian grid, in [L km ~> 1000] or [L m-1 ~> 1] or
200 !! is 0 for a non-Cartesian grid.
201 real :: south_lat !< The latitude (or y-coordinate) of the first v-line [degrees_N] or [km] or [m]
202 real :: west_lon !< The longitude (or x-coordinate) of the first u-line [degrees_E] or [km] or [m]
203 real :: len_lat !< The latitudinal (or y-coord) extent of physical domain [degrees_N] or [km] or [m]
204 real :: len_lon !< The longitudinal (or x-coord) extent of physical domain [degrees_E] or [km] or [m]
205 real :: Rad_Earth_L !< The radius of the planet in rescaled units [L ~> m]
206 real :: max_depth !< The maximum depth of the ocean [Z ~> m]
207end type dyn_horgrid_type
208
209contains
210
211!---------------------------------------------------------------------
212!> Allocate memory used by the dyn_horgrid_type and related structures.
2131subroutine create_dyn_horgrid(G, HI, bathymetry_at_vel)
214 type(dyn_horgrid_type), pointer, intent(inout) :: G !< A pointer to the dynamic horizontal grid type
215 type(hor_index_type), intent(in) :: HI !< A hor_index_type for array extents
216 logical, optional, intent(in) :: bathymetry_at_vel !< If true, there are
217 !! separate values for the basin depths at velocity
218 !! points. Otherwise the effects of topography are
219 !! entirely determined from thickness points.
220 integer :: isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB, isg, ieg, jsg, jeg
221
222 ! This subroutine allocates the lateral elements of the dyn_horgrid_type that
223 ! are always used and zeros them out.
224
2251 if (associated(G)) then
2260 call MOM_error(WARNING, "create_dyn_horgrid called with an associated horgrid_type.")
227 else
2281 allocate(G)
229 endif
230
2311 G%HI = HI
232
2331 G%isc = HI%isc ; G%iec = HI%iec ; G%jsc = HI%jsc ; G%jec = HI%jec
2341 G%isd = HI%isd ; G%ied = HI%ied ; G%jsd = HI%jsd ; G%jed = HI%jed
2351 G%isg = HI%isg ; G%ieg = HI%ieg ; G%jsg = HI%jsg ; G%jeg = HI%jeg
236
2371 G%IscB = HI%IscB ; G%IecB = HI%IecB ; G%JscB = HI%JscB ; G%JecB = HI%JecB
2381 G%IsdB = HI%IsdB ; G%IedB = HI%IedB ; G%JsdB = HI%JsdB ; G%JedB = HI%JedB
2391 G%IsgB = HI%IsgB ; G%IegB = HI%IegB ; G%JsgB = HI%JsgB ; G%JegB = HI%JegB
240
2411 G%idg_offset = HI%idg_offset ; G%jdg_offset = HI%jdg_offset
2421 G%isd_global = G%isd + HI%idg_offset ; G%jsd_global = G%jsd + HI%jdg_offset
2431 G%symmetric = HI%symmetric
244
2451 G%bathymetry_at_vel = .false.
2461 if (present(bathymetry_at_vel)) G%bathymetry_at_vel = bathymetry_at_vel
247
2481 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
2491 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
2501 isg = G%isg ; ieg = G%ieg ; jsg = G%jsg ; jeg = G%jeg
251
2528773 allocate(G%dxT(isd:ied,jsd:jed), source=0.0)
2538841 allocate(G%dxCu(IsdB:IedB,jsd:jed), source=0.0)
2548902 allocate(G%dxCv(isd:ied,JsdB:JedB), source=0.0)
2558971 allocate(G%dxBu(IsdB:IedB,JsdB:JedB), source=0.0)
2568773 allocate(G%IdxT(isd:ied,jsd:jed), source=0.0)
2578841 allocate(G%IdxCu(IsdB:IedB,jsd:jed), source=0.0)
2588841 allocate(G%IdxCu_OBCmask(IsdB:IedB,jsd:jed), source=0.0)
2598902 allocate(G%IdxCv(isd:ied,JsdB:JedB), source=0.0)
2608971 allocate(G%IdxBu(IsdB:IedB,JsdB:JedB), source=0.0)
261
2628773 allocate(G%dyT(isd:ied,jsd:jed), source=0.0)
2638841 allocate(G%dyCu(IsdB:IedB,jsd:jed), source=0.0)
2648902 allocate(G%dyCv(isd:ied,JsdB:JedB), source=0.0)
2658971 allocate(G%dyBu(IsdB:IedB,JsdB:JedB), source=0.0)
2668773 allocate(G%IdyT(isd:ied,jsd:jed), source=0.0)
2678841 allocate(G%IdyCu(IsdB:IedB,jsd:jed), source=0.0)
2688902 allocate(G%IdyCv(isd:ied,JsdB:JedB), source=0.0)
2698902 allocate(G%IdyCv_OBCmask(isd:ied,JsdB:JedB), source=0.0)
2708971 allocate(G%IdyBu(IsdB:IedB,JsdB:JedB), source=0.0)
271
2728773 allocate(G%areaT(isd:ied,jsd:jed), source=0.0)
2738773 allocate(G%IareaT(isd:ied,jsd:jed), source=0.0)
2748971 allocate(G%areaBu(IsdB:IedB,JsdB:JedB), source=0.0)
2758971 allocate(G%IareaBu(IsdB:IedB,JsdB:JedB), source=0.0)
276
2778773 allocate(G%mask2dT(isd:ied,jsd:jed), source=0.0)
2788841 allocate(G%mask2dCu(IsdB:IedB,jsd:jed), source=0.0)
2798902 allocate(G%mask2dCv(isd:ied,JsdB:JedB), source=0.0)
2808971 allocate(G%mask2dBu(IsdB:IedB,JsdB:JedB), source=0.0)
2818841 allocate(G%OBCmaskCu(IsdB:IedB,jsd:jed), source=0.0)
2828902 allocate(G%OBCmaskCv(isd:ied,JsdB:JedB), source=0.0)
2838773 allocate(G%geoLatT(isd:ied,jsd:jed), source=0.0)
2848841 allocate(G%geoLatCu(IsdB:IedB,jsd:jed), source=0.0)
2858902 allocate(G%geoLatCv(isd:ied,JsdB:JedB), source=0.0)
2868971 allocate(G%geoLatBu(IsdB:IedB,JsdB:JedB), source=0.0)
2878773 allocate(G%geoLonT(isd:ied,jsd:jed), source=0.0)
2888841 allocate(G%geoLonCu(IsdB:IedB,jsd:jed), source=0.0)
2898902 allocate(G%geoLonCv(isd:ied,JsdB:JedB), source=0.0)
2908971 allocate(G%geoLonBu(IsdB:IedB,JsdB:JedB), source=0.0)
291
2928902 allocate(G%dx_Cv(isd:ied,JsdB:JedB), source=0.0)
2938841 allocate(G%dy_Cu(IsdB:IedB,jsd:jed), source=0.0)
294
2958841 allocate(G%areaCu(IsdB:IedB,jsd:jed), source=0.0)
2968902 allocate(G%areaCv(isd:ied,JsdB:JedB), source=0.0)
2978841 allocate(G%IareaCu(IsdB:IedB,jsd:jed), source=0.0)
2988902 allocate(G%IareaCv(isd:ied,JsdB:JedB), source=0.0)
299
3008841 allocate(G%porous_DminU(IsdB:IedB,jsd:jed), source=0.0)
3018841 allocate(G%porous_DmaxU(IsdB:IedB,jsd:jed), source=0.0)
3028841 allocate(G%porous_DavgU(IsdB:IedB,jsd:jed), source=0.0)
303
3048902 allocate(G%porous_DminV(isd:ied,JsdB:JedB), source=0.0)
3058902 allocate(G%porous_DmaxV(isd:ied,JsdB:JedB), source=0.0)
3068902 allocate(G%porous_DavgV(isd:ied,JsdB:JedB), source=0.0)
307
3088773 allocate(G%bathyT(isd:ied, jsd:jed), source=0.0)
3098773 allocate(G%meanSL(isd:ied, jsd:jed), source=0.0)
3108971 allocate(G%CoriolisBu(IsdB:IedB, JsdB:JedB), source=0.0)
3118971 allocate(G%Coriolis2Bu(IsdB:IedB, JsdB:JedB), source=0.0)
3128773 allocate(G%dF_dx(isd:ied, jsd:jed), source=0.0)
3138773 allocate(G%dF_dy(isd:ied, jsd:jed), source=0.0)
314
3158773 allocate(G%sin_rot(isd:ied,jsd:jed), source=0.0)
3168773 allocate(G%cos_rot(isd:ied,jsd:jed), source=1.0)
317
3181 if (G%bathymetry_at_vel) then
3190 allocate(G%Dblock_u(IsdB:IedB, jsd:jed), source=0.0)
3200 allocate(G%Dopen_u(IsdB:IedB, jsd:jed), source=0.0)
3210 allocate(G%Dblock_v(isd:ied, JsdB:JedB), source=0.0)
3220 allocate(G%Dopen_v(isd:ied, JsdB:JedB), source=0.0)
323 endif
324
325 ! gridLonB and gridLatB are used as edge values in some cases, so they
326 ! always need to use symmetric memory allcoations.
327121 allocate(G%gridLonT(isg:ieg), source=0.0)
328122 allocate(G%gridLonB(isg-1:ieg), source=0.0)
32961 allocate(G%gridLatT(jsg:jeg), source=0.0)
33062 allocate(G%gridLatB(jsg-1:jeg), source=0.0)
331
3321end subroutine create_dyn_horgrid
333
334
335!> Copy the rotated contents of one horizontal grid type into another. The input
336!! and output grid type arguments can not use the same object.
3370subroutine rotate_dyn_horgrid(G_in, G, US, turns)
338 type(dyn_horgrid_type), intent(in) :: G_in !< The input horizontal grid type
339 type(dyn_horgrid_type), intent(inout) :: G !< An output rotated horizontal grid type
340 !! that has already been allocated, but whose
341 !! contents are largely replaced here.
342 type(unit_scale_type), intent(in) :: US !< A dimensional unit scaling type
343 integer, intent(in) :: turns !< Number of quarter turns
344
345 ! Center point
3460 call rotate_array(G_in%geoLonT, turns, G%geoLonT)
3470 call rotate_array(G_in%geoLatT, turns, G%geoLatT)
3480 call rotate_array_pair(G_in%dxT, G_in%dyT, turns, G%dxT, G%dyT)
3490 call rotate_array(G_in%areaT, turns, G%areaT)
3500 call rotate_array(G_in%bathyT, turns, G%bathyT)
3510 call rotate_array(G_in%meanSL, turns, G%meanSL)
352
3530 call rotate_array_pair(G_in%df_dx, G_in%df_dy, turns, G%df_dx, G%df_dy)
3540 call rotate_array(G_in%sin_rot, turns, G%sin_rot)
3550 call rotate_array(G_in%cos_rot, turns, G%cos_rot)
3560 call rotate_array(G_in%mask2dT, turns, G%mask2dT)
357
358 ! Face points
3590 call rotate_array_pair(G_in%geoLonCu, G_in%geoLonCv, turns, G%geoLonCu, G%geoLonCv)
3600 call rotate_array_pair(G_in%geoLatCu, G_in%geoLatCv, turns, G%geoLatCu, G%geoLatCv)
3610 call rotate_array_pair(G_in%dxCu, G_in%dyCv, turns, G%dxCu, G%dyCv)
3620 call rotate_array_pair(G_in%dxCv, G_in%dyCu, turns, G%dxCv, G%dyCu)
3630 call rotate_array_pair(G_in%dx_Cv, G_in%dy_Cu, turns, G%dx_Cv, G%dy_Cu)
364
3650 call rotate_array_pair(G_in%mask2dCu, G_in%mask2dCv, turns, G%mask2dCu, G%mask2dCv)
3660 call rotate_array_pair(G_in%OBCmaskCu, G_in%OBCmaskCv, turns, G%OBCmaskCu, G%OBCmaskCv)
3670 call rotate_array_pair(G_in%areaCu, G_in%areaCv, turns, G%areaCu, G%areaCv)
3680 call rotate_array_pair(G_in%IareaCu, G_in%IareaCv, turns, G%IareaCu, G%IareaCv)
369
370 call rotate_array_pair(G_in%porous_DminU, G_in%porous_DminV, &
3710 turns, G%porous_DminU, G%porous_DminV)
372 call rotate_array_pair(G_in%porous_DmaxU, G_in%porous_DmaxV, &
3730 turns, G%porous_DmaxU, G%porous_DmaxV)
374 call rotate_array_pair(G_in%porous_DavgU, G_in%porous_DavgV, &
3750 turns, G%porous_DavgU, G%porous_DavgV)
376
377
378 ! Vertex point
3790 call rotate_array(G_in%geoLonBu, turns, G%geoLonBu)
3800 call rotate_array(G_in%geoLatBu, turns, G%geoLatBu)
3810 call rotate_array_pair(G_in%dxBu, G_in%dyBu, turns, G%dxBu, G%dyBu)
3820 call rotate_array(G_in%areaBu, turns, G%areaBu)
3830 call rotate_array(G_in%CoriolisBu, turns, G%CoriolisBu)
3840 call rotate_array(G_in%Coriolis2Bu, turns, G%Coriolis2Bu)
3850 call rotate_array(G_in%mask2dBu, turns, G%mask2dBu)
386
387 ! Topography at the cell faces
3880 G%bathymetry_at_vel = G_in%bathymetry_at_vel
3890 if (G%bathymetry_at_vel) then
3900 call rotate_array_pair(G_in%Dblock_u, G_in%Dblock_v, turns, G%Dblock_u, G%Dblock_v)
3910 call rotate_array_pair(G_in%Dopen_u, G_in%Dopen_v, turns, G%Dopen_u, G%Dopen_v)
392 endif
393
394 ! Nominal grid axes
395 ! TODO: We should not assign lat values to the lon axis, and vice versa.
396 ! We temporarily copy lat <-> lon since several components still expect
397 ! lat and lon sizes to match the first and second dimension sizes.
398 ! But we ought to instead leave them unchanged and adjust the references to
399 ! these axes.
4000 if (modulo(turns, 2) /= 0) then
4010 G%gridLonT(:) = G_in%gridLatT(G_in%jeg:G_in%jsg:-1)
4020 G%gridLatT(:) = G_in%gridLonT(:)
4030 G%gridLonB(:) = G_in%gridLatB(G_in%jeg:(G_in%jsg-1):-1)
4040 G%gridLatB(:) = G_in%gridLonB(:)
405 else
4060 G%gridLonT(:) = G_in%gridLonT(:)
4070 G%gridLatT(:) = G_in%gridLatT(:)
4080 G%gridLonB(:) = G_in%gridLonB(:)
4090 G%gridLatB(:) = G_in%gridLatB(:)
410 endif
411
4120 G%x_axis_units = G_in%y_axis_units
4130 G%y_axis_units = G_in%x_axis_units
4140 G%x_ax_unit_short = G_in%y_ax_unit_short
4150 G%y_ax_unit_short = G_in%x_ax_unit_short
4160 G%south_lat = G_in%south_lat
4170 G%west_lon = G_in%west_lon
4180 G%len_lat = G_in%len_lat
4190 G%len_lon = G_in%len_lon
420
421 ! Rotation-invariant fields
4220 G%grid_unit_to_L = G_in%grid_unit_to_L
4230 G%areaT_global = G_in%areaT_global
4240 G%IareaT_global = G_in%IareaT_global
4250 G%Rad_Earth_L = G_in%Rad_Earth_L
4260 G%max_depth = G_in%max_depth
427
4280 call set_derived_dyn_horgrid(G, US)
4290end subroutine rotate_dyn_horgrid
430
431
432!> rescale_dyn_horgrid_bathymetry permits a change in the internal units for the bathymetry on the
433!! grid, both rescaling the depths and recording the new internal depth units.
4340subroutine rescale_dyn_horgrid_bathymetry(G, m_in_new_units)
435 type(dyn_horgrid_type), intent(inout) :: G !< The dynamic horizontal grid type
436 real, intent(in) :: m_in_new_units !< The new internal representation of 1 m depth [m Z-1 ~> 1]
437
438 ! Local variables
439 real :: rescale ! The inverse of m_in_new_units, used in rescaling bathymetry [Z m-1 ~> 1]
440 integer :: i, j, isd, ied, jsd, jed, IsdB, IedB, JsdB, JedB
441
4420 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
4430 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
444
4450 if (m_in_new_units == 1.0) return
4460 if (m_in_new_units < 0.0) &
4470 call MOM_error(FATAL, "rescale_dyn_horgrid_bathymetry: Negative depth units are not permitted.")
4480 if (m_in_new_units == 0.0) &
4490 call MOM_error(FATAL, "rescale_dyn_horgrid_bathymetry: Zero depth units are not permitted.")
450
4510 rescale = 1.0 / m_in_new_units
4520 do j=jsd,jed ; do i=isd,ied
4530 G%bathyT(i,j) = rescale*G%bathyT(i,j)
4540 G%meanSL(i,j) = rescale*G%meanSL(i,j)
455 enddo ; enddo
4560 if (G%bathymetry_at_vel) then ; do j=jsd,jed ; do I=IsdB,IedB
4570 G%Dblock_u(I,j) = rescale*G%Dblock_u(I,j) ; G%Dopen_u(I,j) = rescale*G%Dopen_u(I,j)
458 enddo ; enddo ; endif
4590 if (G%bathymetry_at_vel) then ; do J=JsdB,JedB ; do i=isd,ied
4600 G%Dblock_v(i,J) = rescale*G%Dblock_v(i,J) ; G%Dopen_v(i,J) = rescale*G%Dopen_v(i,J)
461 enddo ; enddo ; endif
4620 G%max_depth = rescale*G%max_depth
463
464end subroutine rescale_dyn_horgrid_bathymetry
465
466!> set_derived_dyn_horgrid calculates metric terms that are derived from other metrics.
4671subroutine set_derived_dyn_horgrid(G, US)
468 type(dyn_horgrid_type), intent(inout) :: G !< The dynamic horizontal grid type
469 type(unit_scale_type), optional, intent(in) :: US !< A dimensional unit scaling type
470! Various inverse grid spacings and derived areas are calculated within this
471! subroutine.
472 integer :: i, j, isd, ied, jsd, jed
473 integer :: IsdB, IedB, JsdB, JedB
474
4751 isd = G%isd ; ied = G%ied ; jsd = G%jsd ; jed = G%jed
4761 IsdB = G%IsdB ; IedB = G%IedB ; JsdB = G%JsdB ; JedB = G%JedB
477
4788773 do j=jsd,jed ; do i=isd,ied
4798704 if (G%dxT(i,j) < 0.0) G%dxT(i,j) = 0.0
4808704 if (G%dyT(i,j) < 0.0) G%dyT(i,j) = 0.0
4818704 G%IdxT(i,j) = Adcroft_reciprocal(G%dxT(i,j))
4828704 G%IdyT(i,j) = Adcroft_reciprocal(G%dyT(i,j))
4838772 G%IareaT(i,j) = Adcroft_reciprocal(G%areaT(i,j))
484 enddo ; enddo
485
4868841 do j=jsd,jed ; do I=IsdB,IedB
4878772 if (G%dxCu(I,j) < 0.0) G%dxCu(I,j) = 0.0
4888772 if (G%dyCu(I,j) < 0.0) G%dyCu(I,j) = 0.0
4898772 G%IdxCu(I,j) = Adcroft_reciprocal(G%dxCu(I,j))
4908772 G%IdyCu(I,j) = Adcroft_reciprocal(G%dyCu(I,j))
4918840 G%IdxCu_OBCmask(I,j) = G%OBCmaskCu(I,j) * G%IdxCu(I,j) ! This may be reset when the masks are set.
492 enddo ; enddo
493
4948902 do J=JsdB,JedB ; do i=isd,ied
4958832 if (G%dxCv(i,J) < 0.0) G%dxCv(i,J) = 0.0
4968832 if (G%dyCv(i,J) < 0.0) G%dyCv(i,J) = 0.0
4978832 G%IdxCv(i,J) = Adcroft_reciprocal(G%dxCv(i,J))
4988832 G%IdyCv(i,J) = Adcroft_reciprocal(G%dyCv(i,J))
4998901 G%IdyCv_OBCmask(i,J) = G%OBCmaskCv(i,J) * G%IdyCv(i,J) ! This may be reset when the masks are set.
500 enddo ; enddo
501
5028971 do J=JsdB,JedB ; do I=IsdB,IedB
5038901 if (G%dxBu(I,J) < 0.0) G%dxBu(I,J) = 0.0
5048901 if (G%dyBu(I,J) < 0.0) G%dyBu(I,J) = 0.0
505
5068901 G%IdxBu(I,J) = Adcroft_reciprocal(G%dxBu(I,J))
5078901 G%IdyBu(I,J) = Adcroft_reciprocal(G%dyBu(I,J))
508 ! areaBu has usually been set to a positive area elsewhere.
5098901 if (G%areaBu(I,J) <= 0.0) G%areaBu(I,J) = G%dxBu(I,J) * G%dyBu(I,J)
5108970 G%IareaBu(I,J) = Adcroft_reciprocal(G%areaBu(I,J))
511 enddo ; enddo
512
5131end subroutine set_derived_dyn_horgrid
514
515!> Adcroft_reciprocal(x) = 1/x for |x|>0 or 0 for x=0.
51688023function Adcroft_reciprocal(val) result(I_val)
517 real, intent(in) :: val !< The value being inverted in arbitrary units [A ~> a]
518 real :: I_val !< The Adcroft reciprocal of val [A-1 ~> a-1].
519
52088023 I_val = 0.0 ; if (val /= 0.0) I_val = 1.0/val
52188023end function Adcroft_reciprocal
522
523!---------------------------------------------------------------------
524!> Release memory used by the dyn_horgrid_type and related structures.
5251subroutine destroy_dyn_horgrid(G)
526 type(dyn_horgrid_type), pointer :: G !< The dynamic horizontal grid type
527
5281 if (.not.associated(G)) then
5290 call MOM_error(FATAL, "destroy_dyn_horgrid called with an unassociated horgrid_type.")
530 endif
531
5321 deallocate(G%dxT) ; deallocate(G%dxCu) ; deallocate(G%dxCv) ; deallocate(G%dxBu)
5331 deallocate(G%IdxT) ; deallocate(G%IdxCu) ; deallocate(G%IdxCv) ; deallocate(G%IdxBu)
534
5351 deallocate(G%dyT) ; deallocate(G%dyCu) ; deallocate(G%dyCv) ; deallocate(G%dyBu)
5361 deallocate(G%IdyT) ; deallocate(G%IdyCu) ; deallocate(G%IdyCv) ; deallocate(G%IdyBu)
537
5381 deallocate(G%areaT) ; deallocate(G%IareaT)
5391 deallocate(G%areaBu) ; deallocate(G%IareaBu)
5401 deallocate(G%areaCu) ; deallocate(G%IareaCu)
5411 deallocate(G%areaCv) ; deallocate(G%IareaCv)
542
5431 deallocate(G%mask2dT) ; deallocate(G%mask2dCu) ; deallocate(G%OBCmaskCu)
5441 deallocate(G%mask2dCv) ; deallocate(G%OBCmaskCv) ; deallocate(G%mask2dBu)
5451 deallocate(G%IdxCu_OBCmask) ; deallocate(G%IdyCv_OBCmask)
546
5471 deallocate(G%geoLatT) ; deallocate(G%geoLatCu)
5481 deallocate(G%geoLatCv) ; deallocate(G%geoLatBu)
5491 deallocate(G%geoLonT) ; deallocate(G%geoLonCu)
5501 deallocate(G%geoLonCv) ; deallocate(G%geoLonBu)
551
5521 deallocate(G%dx_Cv) ; deallocate(G%dy_Cu)
553
5541 deallocate(G%porous_DminU) ; deallocate(G%porous_DmaxU) ; deallocate(G%porous_DavgU)
5551 deallocate(G%porous_DminV) ; deallocate(G%porous_DmaxV) ; deallocate(G%porous_DavgV)
556
5571 deallocate(G%bathyT) ; deallocate(G%meanSL)
5581 deallocate(G%CoriolisBu) ; deallocate(G%Coriolis2Bu)
5591 deallocate(G%dF_dx) ; deallocate(G%dF_dy)
5601 deallocate(G%sin_rot) ; deallocate(G%cos_rot)
561
5621 if (allocated(G%Dblock_u)) deallocate(G%Dblock_u)
5631 if (allocated(G%Dopen_u)) deallocate(G%Dopen_u)
5641 if (allocated(G%Dblock_v)) deallocate(G%Dblock_v)
5651 if (allocated(G%Dopen_v)) deallocate(G%Dopen_v)
566
5671 deallocate(G%gridLonT) ; deallocate(G%gridLatT)
5681 deallocate(G%gridLonB) ; deallocate(G%gridLatB)
569
570 ! CS%debug is required to validate Domain_aux, so use allocation test
5711 if (associated(G%Domain_aux)) call deallocate_MOM_domain(G%Domain_aux)
572
5731 call deallocate_MOM_domain(G%Domain)
574
5751 deallocate(G)
576
5771end subroutine destroy_dyn_horgrid
578
5790end module MOM_dyn_horgrid