FMS  2024.03
Flexible Modeling System
gaussian_topog.inc
1 !***********************************************************************
2 !* GNU Lesser General Public License
3 !*
4 !* This file is part of the GFDL Flexible Modeling System (FMS).
5 !*
6 !* FMS is free software: you can redistribute it and/or modify it under
7 !* the terms of the GNU Lesser General Public License as published by
8 !* the Free Software Foundation, either version 3 of the License, or (at
9 !* your option) any later version.
10 !*
11 !* FMS is distributed in the hope that it will be useful, but WITHOUT
12 !* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 !* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 !* for more details.
15 !*
16 !* You should have received a copy of the GNU Lesser General Public
17 !* License along with FMS. If not, see <http://www.gnu.org/licenses/>.
18 !***********************************************************************
19 !> @defgroup gaussian_topog_mod gaussian_topog_mod
20 !> @ingroup topography
21 !> @brief Routines for creating Gaussian-shaped land surface topography
22 !! for latitude-longitude grids.
23 !> @author Bruce Wyman
24 !!
25 !! Interfaces generate simple Gaussian-shaped mountains from
26 !! parameters specified by either argument list or namelist input.
27 !! The mountain shapes are controlled by the height, half-width,
28 !! and ridge-width parameters.
29 
30 !> @addtogroup gaussian_topog_mod
31 !> @{
32 
33 !#######################################################################
34 !> @brief Returns a simple surface height field that consists of a single
35 !! Gaussian-shaped mountain.
36 !!
37 !> Returns a surface height field that consists
38 !! of the sum of one or more Gaussian-shaped mountains.
39 !!
40 subroutine gaussian_topog_init_ ( lon, lat, zsurf )
41 
42 real(kind=fms_top_kind_), intent(in) :: lon(:) !< The mean grid box longitude in radians
43 real(kind=fms_top_kind_), intent(in) :: lat(:) !< The mean grid box latitude in radians
44 real(kind=fms_top_kind_), intent(out) :: zsurf(:,:) !< The surface height (meters). Size must be size(lon) by size(lat)
45 
46 integer :: n
47 integer, parameter :: lkind=fms_top_kind_ !local FMS_TOP_KIND_ kind
48 
49  if (.not.module_is_initialized) then
50  call write_version_number("GAUSSIAN_TOPOG_MOD", version)
51  endif
52 
53  if(any(shape(zsurf) /= (/size(lon(:)),size(lat(:))/))) then
54  call error_mesg ('get_gaussian_topog in topography_mod', &
55  'shape(zsurf) is not equal to (/size(lon),size(lat)/)', fatal)
56  endif
57 
58  if (do_nml) call read_namelist
59 
60 ! compute sum of all non-zero mountains
61  zsurf(:,:) = 0.0_lkind
62  do n = 1, maxmts
63  if ( height(n) == 0.0_r8_kind ) cycle
64  zsurf = zsurf + get_gaussian_topog( lon, lat, real(height(n),lkind), &
65  real(olon(n),lkind), real(olat(n),lkind), real(wlon(n),lkind), &
66  real(wlat(n),lkind), real(rlon(n),lkind), real(rlat(n),lkind))
67  enddo
68  module_is_initialized = .true.
69 
70 end subroutine gaussian_topog_init_
71 !#######################################################################
72 !> The height, position, width, and elongation of the mountain
73 !! is controlled by optional arguments.
74 !! @param real lon The mean grid box longitude in radians.
75 !! @param real lat The mean grid box latitude in radians.
76 !! @param real height Maximum surface height in meters.
77 !! @param real olond, olatd Position/origin of mountain in degrees longitude and latitude.
78 !! This is the location of the maximum height.
79 !! @param real wlond, wlatd Gaussian half-width of mountain in degrees longitude and latitude.
80 !! @param real rlond, rlatd Ridge half-width of mountain in degrees longitude and latitude.
81 !! This is the elongation of the maximum height.
82 !! @param real zsurf The surface height (in meters).
83 !! The size of the returned field is size(lon) by size(lat).
84 !! </OUT>
85 !!
86 !! @throws FATAL shape(zsurf) is not equal to (/size(lon),size(lat)/)
87 !! Check the input grid size and output field size.
88 !! The input grid is defined at the midpoint of grid boxes.
89 !!
90 !! @note
91 !! Mountains do not wrap around the poles.
92 !
93 !! <br>Example usage:
94 !! @code{.F90} zsurf = <B>get_gaussian_topog</B> ( lon, lat, height
95 !! [, olond, olatd, wlond, wlatd, rlond, rlatd ] )@endcode
96 !> Returns a land surface topography that consists of a "set" of
97 !! simple Gaussian-shaped mountains. The height, position,
98 !! width, and elongation of the mountains can be controlled
99 !! by variables in the namelist.
100 function get_gaussian_topog_(lon, lat, height, &
101  olond, olatd, wlond, wlatd, rlond, rlatd ) &
102  result(zsurf )
103 
104 real(kind=fms_top_kind_), intent(in) :: lon(:), lat(:)
105 real(kind=fms_top_kind_), intent(in) :: height
106 real(kind=fms_top_kind_), intent(in), optional :: olond, olatd, wlond, wlatd, rlond, rlatd
107 real(kind=fms_top_kind_) :: zsurf(size(lon,1),size(lat,1))
108 
109 integer :: i, j
110 real(kind=fms_top_kind_) :: olon, olat, wlon, wlat, rlon, rlat
111 real(kind=fms_top_kind_) :: tpi, dtr, dx, dy, xx, yy
112 integer, parameter :: lkind = fms_top_kind_
113 
114  if (do_nml) call read_namelist
115 
116 ! no need to compute mountain if height=0
117  if ( height == 0.0_lkind) then
118  zsurf(:,:) = 0.0_lkind
119  return
120  endif
121 
122  tpi = 2.0_lkind*real(pi, fms_top_kind_)
123  dtr = tpi/360.0_lkind
124 
125 ! defaults and convert degrees to radians (dtr)
126  olon = 90.0_r8_kind*real(dtr, r8_kind); if (present(olond)) olon=real(olond*dtr,r8_kind)
127  olat = 45.0_r8_kind*real(dtr, r8_kind); if (present(olatd)) olat=real(olatd*dtr,r8_kind)
128  wlon = 15.0_r8_kind*real(dtr, r8_kind); if (present(wlond)) wlon=real(wlond*dtr,r8_kind)
129  wlat = 15.0_r8_kind*real(dtr, r8_kind); if (present(wlatd)) wlat=real(wlatd*dtr,r8_kind)
130  rlon = 0.0_r8_kind ; if (present(rlond)) rlon=real(rlond*dtr,r8_kind)
131  rlat = 0.0_r8_kind ; if (present(rlatd)) rlat=real(rlatd*dtr,r8_kind)
132 
133 ! compute gaussian-shaped mountain
134  do j=1,size(lat(:))
135  dy = abs(lat(j) - real(olat,lkind)) ! dist from y origin
136  yy = max(0.0_lkind, dy-real(rlat,lkind))/real(wlat,lkind)
137  do i=1,size(lon(:))
138  dx = abs(lon(i) - real(olon,lkind)) ! dist from x origin
139  dx = min(dx, abs(dx-tpi)) ! To ensure that: -pi <= dx <= pi
140  xx = max(0.0_lkind, dx-real(rlon,lkind))/real(wlon,lkind)
141  zsurf(i,j) = real(height,lkind)*exp(-xx**2 - yy**2)
142  enddo
143  enddo
144 
145 end function get_gaussian_topog_
146 
147 !> @}
148 ! close documentation grouping
real(kind=fms_top_kind_) function, dimension(size(lon, 1), size(lat, 1)) get_gaussian_topog_(lon, lat, height, olond, olatd, wlond, wlatd, rlond, rlatd)
The height, position, width, and elongation of the mountain is controlled by optional arguments.
subroutine gaussian_topog_init_(lon, lat, zsurf)
Returns a simple surface height field that consists of a single Gaussian-shaped mountain.