MODFLOW 6 version 6.9.0.dev0
USGS Modular Hydrologic Model
Loading...
Searching...
No Matches
DisvGeom.f90
Go to the documentation of this file.
1module disvgeom
2
3 use kindmodule, only: dp, i4b
5 implicit none
6 private
7 public :: disvgeomtype
9
11
12 integer(I4B) :: k
13 integer(I4B) :: j
14 integer(I4B) :: nodeusr
15 integer(I4B) :: nodered
16 integer(I4B) :: nlay
17 integer(I4B) :: ncpl
18 logical :: reduced
19 integer(I4B) :: nodes ! number of reduced nodes; nodes = nlay *ncpl when grid is NOT reduced
20 real(dp) :: top
21 real(dp) :: bot
22 real(dp), pointer, dimension(:) :: top_grid => null()
23 real(dp), pointer, dimension(:) :: bot_grid => null()
24 integer(I4B), pointer, dimension(:) :: iavert => null()
25 integer(I4B), pointer, dimension(:) :: javert => null()
26 real(dp), pointer, dimension(:, :) :: vertex_grid => null()
27 real(dp), pointer, dimension(:, :) :: cellxy_grid => null()
28 integer(I4B), pointer, dimension(:, :) :: nodereduced => null() ! nodered = nodereduced(nodeusr)
29 integer(I4B), pointer, dimension(:) :: nodeuser => null() ! nodeusr = nodesuser(nodered)
30
31 contains
32
33 procedure :: init
34 generic :: set => set_kj, set_nodered
35 procedure :: set_kj
36 procedure :: set_nodered
37 procedure :: cell_setup
38 procedure :: cprops
39 procedure :: edge_normal
40 procedure :: connection_vector
41 procedure :: shares_edge
42 procedure :: get_area
43
44 end type disvgeomtype
45
46contains
47
48 !> @brief Initialize
49 !<
50 subroutine init(this, nlay, ncpl, nodes, top_grid, bot_grid, iavert, &
51 javert, vertex_grid, cellxy_grid, nodereduced, nodeuser)
52 ! -- dummy
53 class(disvgeomtype) :: this
54 integer(I4B), intent(in) :: nlay
55 integer(I4B), intent(in) :: ncpl
56 integer(I4B), intent(in) :: nodes
57 real(DP), dimension(nodes), target :: top_grid
58 real(DP), dimension(nodes), target :: bot_grid
59 integer(I4B), dimension(:), target :: iavert
60 integer(I4B), dimension(:), target :: javert
61 real(DP), dimension(:, :), target :: vertex_grid
62 real(DP), dimension(:, :), target :: cellxy_grid
63 integer(I4B), dimension(ncpl, nlay), target :: nodereduced
64 integer(I4B), dimension(nodes), target :: nodeuser
65 ! -- local
66 integer(I4B) :: nodesuser
67 !
68 this%nlay = nlay
69 this%ncpl = ncpl
70 this%nodes = nodes
71 this%top_grid => top_grid
72 this%bot_grid => bot_grid
73 this%iavert => iavert
74 this%javert => javert
75 this%vertex_grid => vertex_grid
76 this%cellxy_grid => cellxy_grid
77 this%nodereduced => nodereduced
78 this%nodeuser => nodeuser
79 nodesuser = ncpl * nlay
80 !
81 if (nodes < nodesuser) then
82 this%reduced = .true.
83 else
84 this%reduced = .false.
85 end if
86 end subroutine init
87
88 !> @brief Set node IDs
89 !<
90 subroutine set_kj(this, k, j)
91 ! -- dummy
92 class(disvgeomtype) :: this
93 integer(I4B), intent(in) :: k
94 integer(I4B), intent(in) :: j
95 !
96 this%k = k
97 this%j = j
98 this%nodeusr = get_node(k, 1, j, this%nlay, 1, this%ncpl)
99 if (this%reduced) then
100 this%nodered = this%nodereduced(k, j)
101 else
102 this%nodered = this%nodeusr
103 end if
104 call this%cell_setup()
105 end subroutine set_kj
106
107 !> @brief Set reduced node number
108 !<
109 subroutine set_nodered(this, nodered)
110 ! -- dummy
111 class(disvgeomtype) :: this
112 integer(I4B), intent(in) :: nodered
113 !
114 this%nodered = nodered
115 !
116 if (this%reduced) then
117 this%nodeusr = this%nodeuser(nodered)
118 else
119 this%nodeusr = nodered
120 end if
121 !
122 call get_jk(this%nodeusr, this%ncpl, this%nlay, this%j, this%k)
123 call this%cell_setup()
124 end subroutine set_nodered
125
126 !> @brief Set top and bottom elevations of grid cell
127 !<
128 subroutine cell_setup(this)
129 ! -- dummy
130 class(disvgeomtype) :: this
131 !
132 this%top = this%top_grid(this%nodered)
133 this%bot = this%bot_grid(this%nodered)
134 end subroutine cell_setup
135
136 subroutine cprops(this, cell2, hwva, cl1, cl2, ax, ihc)
137 ! -- module
138 use constantsmodule, only: dzero, dhalf, done
139 ! -- dummy
140 class(disvgeomtype) :: this
141 type(disvgeomtype) :: cell2
142 real(DP), intent(out) :: hwva
143 real(DP), intent(out) :: cl1
144 real(DP), intent(out) :: cl2
145 real(DP), intent(out) :: ax
146 integer(I4B), intent(out) :: ihc
147 ! -- local
148 integer(I4B) :: ivert1, ivert2
149 integer(I4B) :: istart1, istart2, istop1, istop2
150 real(DP) :: x0, y0, x1, y1, x2, y2
151 !
152 if (this%j == cell2%j) then
153 !
154 ! -- Cells share same j index, so must be a vertical connection
155 ihc = 0
156 hwva = this%get_area()
157 cl1 = dhalf * (this%top - this%bot)
158 cl2 = dhalf * (cell2%top - cell2%bot)
159 ax = dzero
160 else
161 !
162 ! -- Must be horizontal connection
163 ihc = 1
164 istart1 = this%iavert(this%j)
165 istop1 = this%iavert(this%j + 1) - 1
166 istart2 = cell2%iavert(cell2%j)
167 istop2 = this%iavert(cell2%j + 1) - 1
168 call shared_edge(this%javert(istart1:istop1), &
169 this%javert(istart2:istop2), &
170 ivert1, ivert2)
171 if (ivert1 == 0 .or. ivert2 == 0) then
172 !
173 ! -- Cells do not share an edge
174 hwva = dzero
175 cl1 = done
176 cl2 = done
177 else
178 x1 = this%vertex_grid(1, ivert1)
179 y1 = this%vertex_grid(2, ivert1)
180 x2 = this%vertex_grid(1, ivert2)
181 y2 = this%vertex_grid(2, ivert2)
182 hwva = distance(x1, y1, x2, y2)
183 !
184 ! -- cl1
185 x0 = this%cellxy_grid(1, this%j)
186 y0 = this%cellxy_grid(2, this%j)
187 cl1 = distance_normal(x0, y0, x1, y1, x2, y2)
188 !
189 ! -- cl2
190 x0 = this%cellxy_grid(1, cell2%j)
191 y0 = this%cellxy_grid(2, cell2%j)
192 cl2 = distance_normal(x0, y0, x1, y1, x2, y2)
193 !
194 ! -- anglex
195 x1 = this%vertex_grid(1, ivert1)
196 y1 = this%vertex_grid(2, ivert1)
197 x2 = this%vertex_grid(1, ivert2)
198 y2 = this%vertex_grid(2, ivert2)
199 ax = anglex(x1, y1, x2, y2)
200 end if
201 end if
202 end subroutine cprops
203
204 !> @brief Return the x and y components of an outward normal facing vector
205 !<
206 subroutine edge_normal(this, cell2, xcomp, ycomp)
207 ! -- module
208 use constantsmodule, only: dzero, dhalf, done
209 ! -- dummy
210 class(disvgeomtype) :: this
211 type(disvgeomtype) :: cell2
212 real(DP), intent(out) :: xcomp
213 real(DP), intent(out) :: ycomp
214 ! -- local
215 integer(I4B) :: ivert1, ivert2
216 integer(I4B) :: istart1, istart2, istop1, istop2
217 real(DP) :: x1, y1, x2, y2
218 !
219 istart1 = this%iavert(this%j)
220 istop1 = this%iavert(this%j + 1) - 1
221 istart2 = cell2%iavert(cell2%j)
222 istop2 = this%iavert(cell2%j + 1) - 1
223 call shared_edge(this%javert(istart1:istop1), &
224 this%javert(istart2:istop2), &
225 ivert1, ivert2)
226 x1 = this%vertex_grid(1, ivert1)
227 y1 = this%vertex_grid(2, ivert1)
228 x2 = this%vertex_grid(1, ivert2)
229 y2 = this%vertex_grid(2, ivert2)
230 !
231 call line_unit_normal(x1, y1, x2, y2, xcomp, ycomp)
232 end subroutine edge_normal
233
234 !> @brief Return the x y and z components of a unit vector that points from
235 !! from the center of this to the center of cell2, and the straight-line
236 !! connection length
237 !<
238 subroutine connection_vector(this, cell2, nozee, satn, satm, xcomp, &
239 ycomp, zcomp, conlen)
240 ! -- module
241 use constantsmodule, only: dzero, dhalf, done
242 ! -- dummy
243 class(disvgeomtype) :: this
244 type(disvgeomtype) :: cell2
245 logical, intent(in) :: nozee
246 real(DP), intent(in) :: satn
247 real(DP), intent(in) :: satm
248 real(DP), intent(out) :: xcomp
249 real(DP), intent(out) :: ycomp
250 real(DP), intent(out) :: zcomp
251 real(DP), intent(out) :: conlen
252 ! -- local
253 real(DP) :: x1, y1, z1, x2, y2, z2
254 !
255 x1 = this%cellxy_grid(1, this%j)
256 y1 = this%cellxy_grid(2, this%j)
257 x2 = this%cellxy_grid(1, cell2%j)
258 y2 = this%cellxy_grid(2, cell2%j)
259 if (nozee) then
260 z1 = dzero
261 z2 = dzero
262 else
263 z1 = this%bot + dhalf * satn * (this%top - this%bot)
264 z2 = cell2%bot + dhalf * satm * (cell2%top - cell2%bot)
265 end if
266 !
267 call line_unit_vector(x1, y1, z1, x2, y2, z2, xcomp, ycomp, zcomp, &
268 conlen)
269 end subroutine connection_vector
270
271 !> @brief Return true if this shares a horizontal edge with cell2
272 !<
273 function shares_edge(this, cell2) result(l)
274 ! -- dummy
275 class(disvgeomtype) :: this
276 type(disvgeomtype) :: cell2
277 ! -- return
278 logical l
279 ! -- local
280 integer(I4B) :: istart1, istop1, istart2, istop2
281 integer(I4B) :: ivert1, ivert2
282 !
283 istart1 = this%iavert(this%j)
284 istop1 = this%iavert(this%j + 1) - 1
285 istart2 = cell2%iavert(cell2%j)
286 istop2 = this%iavert(cell2%j + 1) - 1
287 call shared_edge(this%javert(istart1:istop1), &
288 this%javert(istart2:istop2), &
289 ivert1, ivert2)
290 l = .true.
291 if (ivert1 == 0 .or. ivert2 == 0) then
292 l = .false.
293 end if
294 end function shares_edge
295
296 !> @brief Find two common vertices shared by cell1 and cell2.
297 !!
298 !! Return 0 if there are no shared edges. Proceed forward through ivlist1
299 !! and backward through ivlist2 as a clockwise face in cell1 must correspond
300 !! to a counter clockwise face in cell2.
301 !<
302 subroutine shared_edge(ivlist1, ivlist2, ivert1, ivert2)
303 ! -- dummy
304 integer(I4B), dimension(:) :: ivlist1
305 integer(I4B), dimension(:) :: ivlist2
306 integer(I4B), intent(out) :: ivert1
307 integer(I4B), intent(out) :: ivert2
308 ! -- local
309 integer(I4B) :: nv1
310 integer(I4B) :: nv2
311 integer(I4B) :: il1
312 integer(I4B) :: il2
313 logical :: found
314 !
315 found = .false.
316 nv1 = size(ivlist1)
317 nv2 = size(ivlist2)
318 ivert1 = 0
319 ivert2 = 0
320 outerloop: do il1 = 1, nv1 - 1
321 do il2 = nv2, 2, -1
322 if (ivlist1(il1) == ivlist2(il2) .and. &
323 ivlist1(il1 + 1) == ivlist2(il2 - 1)) then
324 found = .true.
325 ivert1 = ivlist1(il1)
326 ivert2 = ivlist1(il1 + 1)
327 exit outerloop
328 end if
329 end do
330 if (found) exit
331 end do outerloop
332 end subroutine shared_edge
333
334 !> @brief Calculate and return the area of the cell
335 !!
336 !! a = 1/2 *[(x1*y2 + x2*y3 + x3*y4 + ... + xn*y1) -
337 !! (x2*y1 + x3*y2 + x4*y3 + ... + x1*yn)]
338 !<
339 function get_area(this) result(area)
340 ! -- module
341 use constantsmodule, only: dzero, dhalf
342 ! -- dummy
343 class(disvgeomtype) :: this
344 ! -- return
345 real(dp) :: area
346 ! -- local
347 integer(I4B) :: ivert
348 integer(I4B) :: nvert
349 integer(I4B) :: icount
350 integer(I4B) :: iv1
351 real(dp) :: x
352 real(dp) :: y
353 real(dp) :: x1
354 real(dp) :: y1
355 !
356 area = dzero
357 nvert = this%iavert(this%j + 1) - this%iavert(this%j)
358 icount = 1
359 iv1 = this%javert(this%iavert(this%j))
360 x1 = this%vertex_grid(1, iv1)
361 y1 = this%vertex_grid(2, iv1)
362 do ivert = this%iavert(this%j), this%iavert(this%j + 1) - 1
363 x = this%vertex_grid(1, this%javert(ivert))
364 if (icount < nvert) then
365 y = this%vertex_grid(2, this%javert(ivert + 1))
366 else
367 y = this%vertex_grid(2, this%javert(this%iavert(this%j)))
368 end if
369 area = area + (x - x1) * (y - y1)
370 icount = icount + 1
371 end do
372 !
373 icount = 1
374 do ivert = this%iavert(this%j), this%iavert(this%j + 1) - 1
375 y = this%vertex_grid(2, this%javert(ivert))
376 if (icount < nvert) then
377 x = this%vertex_grid(1, this%javert(ivert + 1))
378 else
379 x = this%vertex_grid(1, this%javert(this%iavert(this%j)))
380 end if
381 area = area - (x - x1) * (y - y1)
382 icount = icount + 1
383 end do
384 !
385 area = abs(area) * dhalf
386 end function get_area
387
388 !> @brief Calculate the angle that the x-axis makes with a line that is
389 !! normal to the two points.
390 !!
391 !! This assumes that vertices are numbered clockwise so that the angle is for
392 !! the normal outward of cell n.
393 !<
394 function anglex(x1, y1, x2, y2) result(ax)
395 ! -- modules
396 use constantsmodule, only: dzero, dtwo, dpi
397 ! -- dummy
398 real(dp), intent(in) :: x1
399 real(dp), intent(in) :: x2
400 real(dp), intent(in) :: y1
401 real(dp), intent(in) :: y2
402 ! -- return
403 real(dp) :: ax
404 ! -- local
405 real(dp) :: dx
406 real(dp) :: dy
407 !
408 dx = x2 - x1
409 dy = y2 - y1
410 ax = atan2(dx, -dy)
411 if (ax < dzero) ax = dtwo * dpi + ax
412 end function anglex
413
414 !> @brief Calculate distance between two points
415 !<
416 function distance(x1, y1, x2, y2) result(d)
417 ! -- dummy
418 real(dp), intent(in) :: x1
419 real(dp), intent(in) :: x2
420 real(dp), intent(in) :: y1
421 real(dp), intent(in) :: y2
422 ! -- return
423 real(dp) :: d
424 !
425 d = (x1 - x2)**2 + (y1 - y2)**2
426 d = sqrt(d)
427 end function distance
428
429 !> @brief Calculate normal distance from point (x0, y0) to line defined by
430 !! two points, (x1, y1), (x2, y2).
431 !<
432 function distance_normal(x0, y0, x1, y1, x2, y2) result(d)
433 ! -- dummy
434 real(dp), intent(in) :: x0
435 real(dp), intent(in) :: y0
436 real(dp), intent(in) :: x1
437 real(dp), intent(in) :: y1
438 real(dp), intent(in) :: x2
439 real(dp), intent(in) :: y2
440 ! -- return
441 real(dp) :: d
442 !
443 d = abs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1))
444 d = d / distance(x1, y1, x2, y2)
445 end function distance_normal
446
447 !> @brief Calculate the normal vector components (xcomp and ycomp) for a line
448 !! defined by two points, (x0, y0), (x1, y1).
449 !<
450 subroutine line_unit_normal(x0, y0, x1, y1, xcomp, ycomp)
451 ! -- dummy
452 real(DP), intent(in) :: x0
453 real(DP), intent(in) :: y0
454 real(DP), intent(in) :: x1
455 real(DP), intent(in) :: y1
456 real(DP), intent(out) :: xcomp
457 real(DP), intent(out) :: ycomp
458 ! -- local
459 real(DP) :: dx, dy, vmag
460 !
461 dx = x1 - x0
462 dy = y1 - y0
463 vmag = sqrt(dx**2 + dy**2)
464 xcomp = -dy / vmag
465 ycomp = dx / vmag
466 end subroutine line_unit_normal
467
468 !> @brief Calculate the vector components (xcomp, ycomp, and zcomp) for a
469 !! line defined by two points, (x0, y0, z0), (x1, y1, z1).
470 !!
471 !! Also return the magnitude of the original vector, vmag.
472 !<
473 subroutine line_unit_vector(x0, y0, z0, x1, y1, z1, &
474 xcomp, ycomp, zcomp, vmag)
475 ! -- dummy
476 real(dp), intent(in) :: x0
477 real(dp), intent(in) :: y0
478 real(dp), intent(in) :: z0
479 real(dp), intent(in) :: x1
480 real(dp), intent(in) :: y1
481 real(dp), intent(in) :: z1
482 real(dp), intent(out) :: xcomp
483 real(dp), intent(out) :: ycomp
484 real(dp), intent(out) :: zcomp
485 real(dp) :: vmag
486 ! -- local
487 real(dp) :: dx, dy, dz
488 !
489 dx = x1 - x0
490 dy = y1 - y0
491 dz = z1 - z0
492 vmag = sqrt(dx**2 + dy**2 + dz**2)
493 xcomp = dx / vmag
494 ycomp = dy / vmag
495 zcomp = dz / vmag
496 end subroutine line_unit_vector
497
498end module disvgeom
This module contains simulation constants.
Definition Constants.f90:9
real(dp), parameter dhalf
real constant 1/2
Definition Constants.f90:68
real(dp), parameter dpi
real constant
real(dp), parameter dzero
real constant zero
Definition Constants.f90:65
real(dp), parameter dtwo
real constant 2
Definition Constants.f90:79
real(dp), parameter done
real constant 1
Definition Constants.f90:76
subroutine cprops(this, cell2, hwva, cl1, cl2, ax, ihc)
Definition DisvGeom.f90:137
real(dp) function anglex(x1, y1, x2, y2)
Calculate the angle that the x-axis makes with a line that is normal to the two points.
Definition DisvGeom.f90:395
subroutine line_unit_normal(x0, y0, x1, y1, xcomp, ycomp)
Calculate the normal vector components (xcomp and ycomp) for a line defined by two points,...
Definition DisvGeom.f90:451
subroutine cell_setup(this)
Set top and bottom elevations of grid cell.
Definition DisvGeom.f90:129
real(dp) function distance_normal(x0, y0, x1, y1, x2, y2)
Calculate normal distance from point (x0, y0) to line defined by two points, (x1, y1),...
Definition DisvGeom.f90:433
subroutine set_nodered(this, nodered)
Set reduced node number.
Definition DisvGeom.f90:110
logical function shares_edge(this, cell2)
Return true if this shares a horizontal edge with cell2.
Definition DisvGeom.f90:274
subroutine, public shared_edge(ivlist1, ivlist2, ivert1, ivert2)
Find two common vertices shared by cell1 and cell2.
Definition DisvGeom.f90:303
subroutine edge_normal(this, cell2, xcomp, ycomp)
Return the x and y components of an outward normal facing vector.
Definition DisvGeom.f90:207
real(dp) function get_area(this)
Calculate and return the area of the cell.
Definition DisvGeom.f90:340
subroutine connection_vector(this, cell2, nozee, satn, satm, xcomp, ycomp, zcomp, conlen)
Return the x y and z components of a unit vector that points from from the center of this to the cent...
Definition DisvGeom.f90:240
subroutine, public line_unit_vector(x0, y0, z0, x1, y1, z1, xcomp, ycomp, zcomp, vmag)
Calculate the vector components (xcomp, ycomp, and zcomp) for a line defined by two points,...
Definition DisvGeom.f90:475
real(dp) function distance(x1, y1, x2, y2)
Calculate distance between two points.
Definition DisvGeom.f90:417
subroutine set_kj(this, k, j)
Set node IDs.
Definition DisvGeom.f90:91
subroutine init(this, nlay, ncpl, nodes, top_grid, bot_grid, iavert, javert, vertex_grid, cellxy_grid, nodereduced, nodeuser)
Initialize.
Definition DisvGeom.f90:52
integer(i4b) function, public get_node(ilay, irow, icol, nlay, nrow, ncol)
Get node number, given layer, row, and column indices for a structured grid. If any argument is inval...
Definition GeomUtil.f90:92
real(dp) function, public area(xv, yv, cw)
Calculate polygon area, with vertices given in CW or CCW order.
Definition GeomUtil.f90:364
subroutine, public get_jk(nodenumber, ncpl, nlay, icpl, ilay)
Get layer index and within-layer node index from node number and grid dimensions. If nodenumber is in...
Definition GeomUtil.f90:137
This module defines variable data types.
Definition kind.f90:8