MOM6
basin_builder.F90
1 !> An idealized topography building system
3 
4 ! This file is part of MOM6. See LICENSE.md for the license.
5 
7 use mom_error_handler, only : mom_mesg, mom_error, fatal, is_root_pe
9 use mom_get_input, only : directories
10 use mom_grid, only : ocean_grid_type
11 use mom_string_functions, only : lowercase
13 
14 implicit none ; private
15 
16 #include <MOM_memory.h>
17 
18 public basin_builder_topography
19 
20 ! This include declares and sets the variable "version".
21 # include "version_variable.h"
22 character(len=40) :: mdl = "basin_builder" !< This module's name.
23 
24 contains
25 
26 !> Constructs idealized topography from simple functions
27 subroutine basin_builder_topography(D, G, param_file, max_depth)
28  type(dyn_horgrid_type), intent(in) :: g !< The dynamic horizontal grid type
29  real, dimension(G%isd:G%ied,G%jsd:G%jed), &
30  intent(out) :: d !< Ocean bottom depth in the units of depth_max
31  type(param_file_type), intent(in) :: param_file !< Parameter file structure
32  real, intent(in) :: max_depth !< Maximum ocean depth in arbitrary units
33  ! Local variables
34  character(len=17) :: pname1, pname2 ! For construction of parameter names
35  character(len=20) :: funcs ! Basin build function
36  real, dimension(20) :: pars ! Parameters for each function
37  real :: lon ! Longitude [degrees_E}
38  real :: lat ! Latitude [degrees_N]
39  integer :: i, j, n, n_funcs
40 
41  call mom_mesg(" basin_builder.F90, basin_builder_topography: setting topography", 5)
42  call log_version(param_file, mdl, version, "")
43 
44  do j=g%jsc,g%jec ; do i=g%isc,g%iec
45  d(i,j) = 1.0
46  enddo ; enddo
47 
48  call get_param(param_file, mdl, "BBUILDER_N", n_funcs, &
49  "Number of pieces of topography to use.", fail_if_missing=.true.)
50 
51  do n=1,n_funcs
52  write( pname1, "('BBUILDER_',i3.3,'_FUNC')" ) n
53  write( pname2, "('BBUILDER_',i3.3,'_PARS')" ) n
54  call get_param(param_file, mdl, pname1, funcs, &
55  "The basin builder function to apply with parameters "//&
56  trim(pname2)//". Choices are: NS_COAST, EW_COAST, "//&
57  "CIRC_CONIC_RIDGE, NS_CONIC_RIDGE, CIRC_SCURVE_RIDGE, "//&
58  "NS_SCURVE_RIDGE.", &
59  fail_if_missing=.true.)
60  pars(:) = 0.
61  if (trim(lowercase(funcs)) == 'ns_coast') then
62  call get_param(param_file, mdl, pname2, pars(1:5), &
63  "NS_COAST parameters: longitude, starting latitude, "//&
64  "ending latitude, footprint radius, shelf depth.", &
65  units="degrees_E,degrees_N,degrees_N,degrees,m", &
66  fail_if_missing=.true.)
67  pars(5) = pars(5) / max_depth
68  do j=g%jsc,g%jec ; do i=g%isc,g%iec
69  lon = g%geoLonT(i,j)
70  lat = g%geoLatT(i,j)
71  d(i,j) = min( d(i,j), ns_coast(lon, lat, pars(1), pars(2), pars(3), pars(4), pars(5)) )
72  enddo ; enddo
73  elseif (trim(lowercase(funcs)) == 'ns_conic_ridge') then
74  call get_param(param_file, mdl, pname2, pars(1:5), &
75  "NS_CONIC_RIDGE parameters: longitude, starting latitude, "//&
76  "ending latitude, footprint radius, ridge height.", &
77  units="degrees_E,degrees_N,degrees_N,degrees,m", &
78  fail_if_missing=.true.)
79  pars(5) = pars(5) / max_depth
80  do j=g%jsc,g%jec ; do i=g%isc,g%iec
81  lon = g%geoLonT(i,j)
82  lat = g%geoLatT(i,j)
83  d(i,j) = min( d(i,j), ns_conic_ridge(lon, lat, pars(1), pars(2), pars(3), pars(4), pars(5)) )
84  enddo ; enddo
85  elseif (trim(lowercase(funcs)) == 'ns_scurve_ridge') then
86  call get_param(param_file, mdl, pname2, pars(1:5), &
87  "NS_SCURVE_RIDGE parameters: longitude, starting latitude, "//&
88  "ending latitude, footprint radius, ridge height.", &
89  units="degrees_E,degrees_N,degrees_N,degrees,m", &
90  fail_if_missing=.true.)
91  pars(5) = pars(5) / max_depth
92  do j=g%jsc,g%jec ; do i=g%isc,g%iec
93  lon = g%geoLonT(i,j)
94  lat = g%geoLatT(i,j)
95  d(i,j) = min( d(i,j), ns_scurve_ridge(lon, lat, pars(1), pars(2), pars(3), pars(4), pars(5)) )
96  enddo ; enddo
97  elseif (trim(lowercase(funcs)) == 'ew_coast') then
98  call get_param(param_file, mdl, pname2, pars(1:5), &
99  "EW_COAST parameters: latitude, starting longitude, "//&
100  "ending longitude, footprint radius, shelf depth.", &
101  units="degrees_N,degrees_E,degrees_E,degrees,m", &
102  fail_if_missing=.true.)
103  pars(5) = pars(5) / max_depth
104  do j=g%jsc,g%jec ; do i=g%isc,g%iec
105  lon = g%geoLonT(i,j)
106  lat = g%geoLatT(i,j)
107  d(i,j) = min( d(i,j), ew_coast(lon, lat, pars(1), pars(2), pars(3), pars(4), pars(5)) )
108  enddo ; enddo
109  elseif (trim(lowercase(funcs)) == 'circ_conic_ridge') then
110  call get_param(param_file, mdl, pname2, pars(1:5), &
111  "CIRC_CONIC_RIDGE parameters: center longitude, center latitude, "//&
112  "ring radius, footprint radius, ridge height.", &
113  units="degrees_E,degrees_N,degrees,degrees,m", &
114  fail_if_missing=.true.)
115  pars(5) = pars(5) / max_depth
116  do j=g%jsc,g%jec ; do i=g%isc,g%iec
117  lon = g%geoLonT(i,j)
118  lat = g%geoLatT(i,j)
119  d(i,j) = min( d(i,j), circ_conic_ridge(lon, lat, pars(1), pars(2), pars(3), pars(4), pars(5)) )
120  enddo ; enddo
121  elseif (trim(lowercase(funcs)) == 'circ_scurve_ridge') then
122  call get_param(param_file, mdl, pname2, pars(1:5), &
123  "CIRC_SCURVe_RIDGE parameters: center longitude, center latitude, "//&
124  "ring radius, footprint radius, ridge height.", &
125  units="degrees_E,degrees_N,degrees,degrees,m", &
126  fail_if_missing=.true.)
127  pars(5) = pars(5) / max_depth
128  do j=g%jsc,g%jec ; do i=g%isc,g%iec
129  lon = g%geoLonT(i,j)
130  lat = g%geoLatT(i,j)
131  d(i,j) = min( d(i,j), circ_scurve_ridge(lon, lat, pars(1), pars(2), pars(3), pars(4), pars(5)) )
132  enddo ; enddo
133  else
134  call mom_error(fatal, "basin_builder.F90, basin_builer_topography:\n"//&
135  "Unrecognized function "//trim(funcs))
136  endif
137 
138  enddo ! n
139 
140  do j=g%jsc,g%jec ; do i=g%isc,g%iec
141  ! Dimensionalize by scaling 1 to max_depth
142  d(i,j) = d(i,j) * max_depth
143  enddo ; enddo
144 
145 end subroutine basin_builder_topography
146 
147 !> Returns the value of a triangular function centered at x=x0 with value 1
148 !! and linearly decreasing to 0 at x=x0+/-L, and 0 otherwise.
149 !! If clip is present the top of the cone is cut off at "clip", which
150 !! effectively defaults to 1.
151 real function cone(x, x0, L, clip)
152  real, intent(in) :: x !< non-dimensional coordinate [nondim]
153  real, intent(in) :: x0 !< position of peak [nondim]
154  real, intent(in) :: l !< half-width of base of cone [nondim]
155  real, optional, intent(in) :: clip !< clipping height of cone [nondim]
156 
157  cone = max( 0., 1. - abs(x - x0) / l )
158  if (present(clip)) cone = min(clip, cone)
159 end function cone
160 
161 !> Returns an s-curve s(x) s.t. s(x0)<=0, s(x0+L)>=1 and cubic in between.
162 real function scurve(x, x0, L)
163  real, intent(in) :: x !< non-dimensional coordinate [nondim]
164  real, intent(in) :: x0 !< position of peak [nondim]
165  real, intent(in) :: l !< half-width of base of cone [nondim]
166  real :: s
167 
168  s = max( 0., min( 1.,( x - x0 ) / l ) )
169  scurve = ( 3. - 2.*s ) * ( s * s )
170 end function scurve
171 
172 !> Returns a "coastal" profile.
173 real function cstprof(x, x0, L, lf, bf, sf, sh)
174  real, intent(in) :: x !< non-dimensional coordinate [nondim]
175  real, intent(in) :: x0 !< position of peak [nondim]
176  real, intent(in) :: l !< width of profile [nondim]
177  real, intent(in) :: lf !< fraction of width that is "land" [nondim]
178  real, intent(in) :: bf !< fraction of width that is "beach" [nondim]
179  real, intent(in) :: sf !< fraction of width that is "continental slope" [nondim]
180  real, intent(in) :: sh !< depth of shelf as fraction of full depth [nondim]
181  real :: s
182 
183  s = max( 0., min( 1.,( x - x0 ) / l ) )
184  cstprof = sh * scurve(s-lf,0.,bf) + (1.-sh) * scurve(s - (1.-sf),0.,sf)
185 end function cstprof
186 
187 !> Distance between points x,y and a line segment (x0,y0) and (x0,y1).
188 real function dist_line_fixed_x(x, y, x0, y0, y1)
189  real, intent(in) :: x !< non-dimensional x-coordinate [nondim]
190  real, intent(in) :: y !< non-dimensional y-coordinate [nondim]
191  real, intent(in) :: x0 !< x-position of line segment [nondim]
192  real, intent(in) :: y0 !< y-position of line segment end[nondim]
193  real, intent(in) :: y1 !< y-position of line segment end[nondim]
194  real :: dx, yr, dy
195 
196  dx = x - x0
197  yr = min( max(y0,y1), max( min(y0,y1), y ) ) ! bound y by y0,y1
198  dy = y - yr ! =0 within y0<y<y1, =y0-y for y<y0, =y-y1 for y>y1
199  dist_line_fixed_x = sqrt( dx*dx + dy*dy )
200 end function dist_line_fixed_x
201 
202 !> Distance between points x,y and a line segment (x0,y0) and (x1,y0).
203 real function dist_line_fixed_y(x, y, x0, x1, y0)
204  real, intent(in) :: x !< non-dimensional x-coordinate [nondim]
205  real, intent(in) :: y !< non-dimensional y-coordinate [nondim]
206  real, intent(in) :: x0 !< x-position of line segment end[nondim]
207  real, intent(in) :: x1 !< x-position of line segment end[nondim]
208  real, intent(in) :: y0 !< y-position of line segment [nondim]
209  real :: dx, yr, dy
210 
211  dist_line_fixed_y = dist_line_fixed_x(y, x, y0, x0, x1)
212 end function dist_line_fixed_y
213 
214 !> A "coast profile" applied in an N-S line from lonC,lat0 to lonC,lat1.
215 real function ns_coast(lon, lat, lonC, lat0, lat1, dlon, sh)
216  real, intent(in) :: lon !< Longitude [degrees_E]
217  real, intent(in) :: lat !< Latitude [degrees_N]
218  real, intent(in) :: lonc !< Longitude of coast [degrees_E]
219  real, intent(in) :: lat0 !< Latitude of coast end [degrees_N]
220  real, intent(in) :: lat1 !< Latitude of coast end [degrees_N]
221  real, intent(in) :: dlon !< "Radius" of coast profile [degrees]
222  real, intent(in) :: sh !< depth of shelf as fraction of full depth [nondim]
223  real :: r
224 
225  r = dist_line_fixed_x( lon, lat, lonc, lat0, lat1 )
226  ns_coast = cstprof(r, 0., dlon, 0.125, 0.125, 0.5, sh)
227 end function ns_coast
228 
229 !> A "coast profile" applied in an E-W line from lon0,latC to lon1,latC.
230 real function ew_coast(lon, lat, latC, lon0, lon1, dlat, sh)
231  real, intent(in) :: lon !< Longitude [degrees_E]
232  real, intent(in) :: lat !< Latitude [degrees_N]
233  real, intent(in) :: latc !< Latitude of coast [degrees_N]
234  real, intent(in) :: lon0 !< Longitude of coast end [degrees_E]
235  real, intent(in) :: lon1 !< Longitude of coast end [degrees_E]
236  real, intent(in) :: dlat !< "Radius" of coast profile [degrees]
237  real, intent(in) :: sh !< depth of shelf as fraction of full depth [nondim]
238  real :: r
239 
240  r = dist_line_fixed_y( lon, lat, lon0, lon1, latc )
241  ew_coast = cstprof(r, 0., dlat, 0.125, 0.125, 0.5, sh)
242 end function ew_coast
243 
244 !> A NS ridge with a cone profile
245 real function ns_conic_ridge(lon, lat, lonC, lat0, lat1, dlon, rh)
246  real, intent(in) :: lon !< Longitude [degrees_E]
247  real, intent(in) :: lat !< Latitude [degrees_N]
248  real, intent(in) :: lonc !< Longitude of ridge center [degrees_E]
249  real, intent(in) :: lat0 !< Latitude of ridge end [degrees_N]
250  real, intent(in) :: lat1 !< Latitude of ridge end [degrees_N]
251  real, intent(in) :: dlon !< "Radius" of ridge profile [degrees]
252  real, intent(in) :: rh !< depth of ridge as fraction of full depth [nondim]
253  real :: r
254 
255  r = dist_line_fixed_x( lon, lat, lonc, lat0, lat1 )
256  ns_conic_ridge = 1. - rh * cone(r, 0., dlon)
257 end function ns_conic_ridge
258 
259 !> A NS ridge with an scurve profile
260 real function ns_scurve_ridge(lon, lat, lonC, lat0, lat1, dlon, rh)
261  real, intent(in) :: lon !< Longitude [degrees_E]
262  real, intent(in) :: lat !< Latitude [degrees_N]
263  real, intent(in) :: lonc !< Longitude of ridge center [degrees_E]
264  real, intent(in) :: lat0 !< Latitude of ridge end [degrees_N]
265  real, intent(in) :: lat1 !< Latitude of ridge end [degrees_N]
266  real, intent(in) :: dlon !< "Radius" of ridge profile [degrees]
267  real, intent(in) :: rh !< depth of ridge as fraction of full depth [nondim]
268  real :: r
269 
270  r = dist_line_fixed_x( lon, lat, lonc, lat0, lat1 )
271  ns_scurve_ridge = 1. - rh * (1. - scurve(r, 0., dlon) )
272 end function ns_scurve_ridge
273 
274 !> A circular ridge with cutoff conic profile
275 real function circ_conic_ridge(lon, lat, lon0, lat0, ring_radius, ring_thickness, ridge_height)
276  real, intent(in) :: lon !< Longitude [degrees_E]
277  real, intent(in) :: lat !< Latitude [degrees_N]
278  real, intent(in) :: lon0 !< Longitude of center of ring [degrees_E]
279  real, intent(in) :: lat0 !< Latitude of center of ring [degrees_N]
280  real, intent(in) :: ring_radius !< Radius of ring [degrees]
281  real, intent(in) :: ring_thickness !< Radial thickness of ring [degrees]
282  real, intent(in) :: ridge_height !< Ridge height as fraction of full depth [nondim]
283  real :: r
284 
285  r = sqrt( (lon - lon0)**2 + (lat - lat0)**2 ) ! Pseudo-distance from a point
286  r = abs( r - ring_radius) ! Pseudo-distance from a circle
287  r = cone(r, 0., ring_thickness, ridge_height) ! 0 .. frac_ridge_height
288  circ_conic_ridge = 1. - r ! nondim depths (1-frac_ridge_height) .. 1
289 end function circ_conic_ridge
290 
291 !> A circular ridge with cutoff scurve profile
292 real function circ_scurve_ridge(lon, lat, lon0, lat0, ring_radius, ring_thickness, ridge_height)
293  real, intent(in) :: lon !< Longitude [degrees_E]
294  real, intent(in) :: lat !< Latitude [degrees_N]
295  real, intent(in) :: lon0 !< Longitude of center of ring [degrees_E]
296  real, intent(in) :: lat0 !< Latitude of center of ring [degrees_N]
297  real, intent(in) :: ring_radius !< Radius of ring [degrees]
298  real, intent(in) :: ring_thickness !< Radial thickness of ring [degrees]
299  real, intent(in) :: ridge_height !< Ridge height as fraction of full depth [nondim]
300  real :: r
301 
302  r = sqrt( (lon - lon0)**2 + (lat - lat0)**2 ) ! Pseudo-distance from a point
303  r = abs( r - ring_radius) ! Pseudo-distance from a circle
304  r = 1. - scurve(r, 0., ring_thickness) ! 0 .. 1
305  r = r * ridge_height ! 0 .. frac_ridge_height
306  circ_scurve_ridge = 1. - r ! nondim depths (1-frac_ridge_height) .. 1
307 end function circ_scurve_ridge
308 
309 end module basin_builder
mom_file_parser::log_version
An overloaded interface to log version information about modules.
Definition: MOM_file_parser.F90:109
mom_get_input::directories
Container for paths and parameter file names.
Definition: MOM_get_input.F90:20
mom_dyn_horgrid
Contains a shareable dynamic type for describing horizontal grids and metric data and utilty routines...
Definition: MOM_dyn_horgrid.F90:3
mom_string_functions
Handy functions for manipulating strings.
Definition: MOM_string_functions.F90:2
mom_file_parser::param_file_type
A structure that can be parsed to read and document run-time parameters.
Definition: MOM_file_parser.F90:54
mom_file_parser::get_param
An overloaded interface to read and log the values of various types of parameters.
Definition: MOM_file_parser.F90:102
mom_get_input
Reads the only Fortran name list needed to boot-strap the model.
Definition: MOM_get_input.F90:6
mom_unit_scaling::unit_scale_type
Describes various unit conversion factors.
Definition: MOM_unit_scaling.F90:14
mom_file_parser
The MOM6 facility to parse input files for runtime parameters.
Definition: MOM_file_parser.F90:2
mom_grid
Provides the ocean grid type.
Definition: MOM_grid.F90:2
mom_unit_scaling
Provides a transparent unit rescaling type to facilitate dimensional consistency testing.
Definition: MOM_unit_scaling.F90:2
basin_builder
An idealized topography building system.
Definition: basin_builder.F90:2
mom_error_handler
Routines for error handling and I/O management.
Definition: MOM_error_handler.F90:2
mom_dyn_horgrid::dyn_horgrid_type
Describes the horizontal ocean grid with only dynamic memory arrays.
Definition: MOM_dyn_horgrid.F90:23
mom_grid::ocean_grid_type
Ocean grid type. See mom_grid for details.
Definition: MOM_grid.F90:26