MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
TernarySolveTrack.f90
Go to the documentation of this file.
2 
3  use kindmodule, only: i4b, dp, lgp
4  use geomutilmodule, only: skew
5  use mathutilmodule, only: f1d, zero_ch, zero_br
6  use errorutilmodule, only: pstop
7 
8  private
9  public :: traverse_triangle
10  public :: canonical
11  public :: get_w
12  public :: solve_coefs
13  public :: step_analytical
14  public :: find_exit_bary
15  public :: get_t_alpt
16  public :: get_bet_outflow_bary
17  public :: get_bet_soln_limits
18  public :: soln_brent
19  public :: soln_chand
20  public :: alpfun
21 
22  ! global data
23  real(dp) ca1, ca2, ca3, cb1, cb2 !< Analytical solution coefficients
24  real(dp) waa, wab, wba, wbb !< Elements of the "velocity matrix," W
25  real(dp) :: cv0(2), cv1(2), cv2(2) !< "Canonical" velocity components at corners of triangular subcell
26  integer(I4B) icase !< Case index for analytical solution
27 
28 contains
29 
30  !> @brief Traverse triangular cell
31  subroutine traverse_triangle(isolv, tol, step, texit, &
32  alpexit, betexit, &
33  itrifaceenter, itrifaceexit, &
34  rxx, rxy, ryx, ryy, &
35  alp0, bet0, alp1, bet1, alp2, bet2, alpi, beti, &
36  vziodz, az, &
37  bary)
38  ! -- dummy
39  integer(I4B), intent(in) :: isolv !< solution method
40  real(dp), intent(in) :: tol !< solution tolerance
41  real(dp), intent(in) :: step !< stepsize for numerical methods
42  real(dp), intent(out) :: texit !< time particle exits the cell
43  real(dp) :: alpexit
44  real(dp) :: betexit !< alpha and beta coefficients
45  integer(I4B) :: itrifaceenter
46  integer(I4B) :: itrifaceexit !< entry and exit faces
47  real(dp) :: rxx
48  real(dp) :: rxy
49  real(dp) :: ryx
50  real(dp) :: ryy !< rotation matrix
51  real(dp) :: alp0
52  real(dp) :: bet0
53  real(dp) :: alp1
54  real(dp) :: bet1
55  real(dp) :: alp2
56  real(dp) :: bet2
57  real(dp) :: alpi
58  real(dp) :: beti !< alpha and beta coefficients
59  real(dp) :: vziodz
60  real(dp) :: az
61  logical(LGP), intent(in) :: bary !< whether to use barycentric coordinates
62  ! -- local
63  real(dp) :: texit0
64  real(dp) :: alpexit0
65  real(dp) :: betexit0
66  real(dp) :: texit1
67  real(dp) :: alpexit1
68  real(dp) :: betexit1
69  real(dp) :: texit2
70  real(dp) :: alpexit2
71  real(dp) :: betexit2
72 
73  ! -- Compute elements of matrix W
74  call get_w(alp1, bet1, alp2, bet2, waa, wab, wba, wbb, bary)
75 
76  ! -- Determine alpha and beta analytically as functions of time
77  call solve_coefs(alpi, beti)
78 
79  ! -- Compute exit time (travel time to exit) and exit location
80  call find_exit_bary(isolv, 0, itrifaceenter, &
81  alpi, beti, &
82  tol, step, vziodz, az, &
83  texit0, alpexit0, betexit0)
84  call find_exit_bary(isolv, 1, itrifaceenter, &
85  alpi, beti, &
86  tol, step, vziodz, az, &
87  texit1, alpexit1, betexit1)
88  call find_exit_bary(isolv, 2, itrifaceenter, &
89  alpi, beti, &
90  tol, step, vziodz, az, &
91  texit2, alpexit2, betexit2)
92  texit = min(texit0, texit1, texit2)
93 
94  ! -- Note that while the numbering of triangle faces is generally zero-based
95  ! -- (0, 1, 2), itrifaceexit, which gets passed out, is one-based (1, 2, 3).
96  if (texit .eq. texit0) then
97  alpexit = alpexit0
98  betexit = betexit0
99  itrifaceexit = 1
100  else if (texit .eq. texit1) then
101  alpexit = alpexit1
102  betexit = betexit1
103  itrifaceexit = 2
104  else if (texit .eq. texit2) then
105  alpexit = alpexit2
106  betexit = betexit2
107  itrifaceexit = 3
108  end if
109  if (texit .eq. huge(1d0)) itrifaceexit = 0
110 
111  end subroutine
112 
113  !> @brief Set coordinates to "canonical" configuration
114  subroutine canonical(x0, y0, x1, y1, x2, y2, &
115  v0x, v0y, v1x, v1y, v2x, v2y, &
116  xi, yi, &
117  rxx, rxy, ryx, ryy, &
118  sxx, sxy, syy, &
119  alp0, bet0, alp1, bet1, alp2, bet2, alpi, beti, &
120  bary)
121  ! -- dummy
122  real(dp) :: x0
123  real(dp) :: y0
124  real(dp) :: x1
125  real(dp) :: y1
126  real(dp) :: x2
127  real(dp) :: y2
128  real(dp) :: v0x
129  real(dp) :: v0y
130  real(dp) :: v1x
131  real(dp) :: v1y
132  real(dp) :: v2x
133  real(dp) :: v2y
134  real(dp) :: xi
135  real(dp) :: yi
136  real(dp) :: rxx
137  real(dp) :: rxy
138  real(dp) :: ryx
139  real(dp) :: ryy !< rotation matrix
140  real(dp), intent(inout) :: sxx, sxy, syy !< skew matrix entries (top left, top right, bottom right)
141  real(dp) :: alp0
142  real(dp) :: bet0
143  real(dp) :: alp1
144  real(dp) :: bet1
145  real(dp) :: alp2
146  real(dp) :: bet2
147  real(dp) :: alpi
148  real(dp) :: beti !< alpha and beta coefficients
149  logical(LGP), intent(in) :: bary !< whether to use barycentric coordinates
150  ! -- local
151  real(dp) :: baselen
152  real(dp) :: oobaselen
153  real(dp) :: sinomega
154  real(dp) :: cosomega
155  real(dp) :: x1diff
156  real(dp) :: y1diff
157  real(dp) :: x2diff
158  real(dp) :: y2diff
159  real(dp) :: xidiff
160  real(dp) :: yidiff
161  real(dp) :: rot(2, 2), res(2)
162 
163  ! -- Translate and rotate coordinates to "canonical" configuration
164  x1diff = x1 - x0
165  y1diff = y1 - y0
166  x2diff = x2 - x0
167  y2diff = y2 - y0
168  baselen = dsqrt(x1diff * x1diff + y1diff * y1diff)
169  oobaselen = 1d0 / baselen
170  cosomega = x1diff * oobaselen
171  sinomega = y1diff * oobaselen
172  rxx = cosomega
173  rxy = sinomega
174  ryx = -sinomega
175  ryy = cosomega
176  alp0 = 0d0
177  bet0 = 0d0
178  alp1 = baselen
179  bet1 = 0d0
180 
181  rot = reshape((/rxx, ryx, rxy, ryy/), shape(rot))
182  res = matmul(rot, (/x2diff, y2diff/))
183  alp2 = res(1)
184  bet2 = res(2)
185 
186  cv0 = matmul(rot, (/v0x, v0y/))
187  cv1 = matmul(rot, (/v1x, v1y/))
188  cv2 = matmul(rot, (/v2x, v2y/))
189 
190  xidiff = xi - x0
191  yidiff = yi - y0
192  res = matmul(rot, (/xidiff, yidiff/))
193  alpi = res(1)
194  beti = res(2)
195 
196  if (bary) then
197  sxx = 1d0 / alp1
198  syy = 1d0 / bet2
199  sxy = -alp2 * sxx * syy
200  alp1 = 1d0
201  alp2 = 0d0
202  bet2 = 1d0
203  cv0 = skew(cv0, (/sxx, sxy, syy/))
204  cv1 = skew(cv1, (/sxx, sxy, syy/))
205  cv2 = skew(cv2, (/sxx, sxy, syy/))
206  res = (/alpi, beti/)
207  res = skew(res, (/sxx, sxy, syy/))
208  alpi = res(1)
209  beti = res(2)
210  end if
211 
212  end subroutine
213 
214  !> @brief Compute elements of W matrix
215  subroutine get_w( &
216  alp1, bet1, alp2, bet2, &
217  waa, wab, wba, wbb, &
218  bary)
219  ! -- dummy
220  real(dp) :: alp1
221  real(dp) :: bet1
222  real(dp) :: alp2
223  real(dp) :: bet2 !< triangle face points
224  real(dp) :: waa
225  real(dp) :: wab
226  real(dp) :: wba
227  real(dp) :: wbb !< w matrix
228  logical(LGP), intent(in), optional :: bary !< barycentric coordinates
229  ! -- local
230  logical(LGP) :: lbary
231  real(dp) :: v1alpdiff
232  real(dp) :: v2alpdiff
233  real(dp) :: v2betdiff
234  real(dp) :: ooalp1
235  real(dp) :: oobet2
236  real(dp) :: vterm
237 
238  if (present(bary)) then
239  lbary = bary
240  else
241  lbary = .true.
242  end if
243 
244  ! -- Note: wab is the "alpha,beta" entry in matrix W
245  ! and the alpha component of the w^(beta) vector
246  v1alpdiff = cv1(1) - cv0(1)
247  v2alpdiff = cv2(1) - cv0(1)
248  v2betdiff = cv2(2) - cv0(2)
249  if (bary) then
250  waa = v1alpdiff
251  wab = v2alpdiff
252  wba = 0d0
253  wbb = v2betdiff
254  else
255  ooalp1 = 1d0 / alp1
256  oobet2 = 1d0 / bet2
257  vterm = v1alpdiff * ooalp1
258  waa = vterm
259  wab = (v2alpdiff - alp2 * vterm) * oobet2
260  wba = 0d0
261  wbb = v2betdiff * oobet2
262  end if
263 
264  end subroutine
265 
266  !> @brief Compute analytical solution coefficients depending on case
267  subroutine solve_coefs(alpi, beti)
268  ! -- dummy
269  real(dp) :: alpi
270  real(dp) :: beti
271  ! -- local
272  real(dp) :: zerotol
273  real(dp) :: wratv
274  real(dp) :: acoef
275  real(dp) :: bcoef
276  real(dp) :: afact
277  real(dp) :: bfact
278  real(dp) :: vfact
279  real(dp) :: oowaa
280 
281  zerotol = 1d-10 ! kluge
282  if (dabs(wbb) .gt. zerotol) then
283  wratv = (wab / wbb) * cv0(2)
284  acoef = cv0(1) - wratv
285  bcoef = wratv + wab * beti
286  afact = acoef / waa
287  vfact = cv0(2) / wbb
288  ! -- Coefs for beta do not depend on whether waa = 0 or not
289  cb1 = -vfact ! const term in beta
290  cb2 = vfact + beti ! coef for e(wbb*t) term in beta
291  ! -- Coefs for alpha
292  if (dabs(waa) .gt. zerotol) then
293  ! -- Case waa <> 0, wbb <> 0
294  if (dabs(wbb - waa) .gt. zerotol) then
295  ! -- Subcase wbb <> waa
296  bfact = bcoef / (wbb - waa)
297  ca1 = -afact ! const term in alpha
298  ca2 = alpi + afact - bfact ! coef for exp(waa*t) term in alpha
299  ca3 = bfact ! coef for exp(wbb*t) term in alpha
300  icase = 1
301  else
302  ! -- Subcase wbb = waa
303  ca1 = -afact ! const term in alpha
304  ca2 = alpi + afact ! coef for exp(waa*t) term in alpha
305  ca3 = bcoef ! coef for t*exp(waa*t) term in alpha
306  icase = -1
307  end if
308  else
309  ! -- Case waa = 0, wbb <> 0
310  bfact = bcoef / wbb
311  ca1 = alpi - bfact ! const term in alpha
312  ca2 = acoef ! coef for t term in alpha
313  ca3 = bfact ! coef for exp(wbb*t) term in alpha
314  icase = 2
315  end if
316  else
317  ! -- Coefs for beta do not depend on whether waa = 0 or not
318  cb1 = beti ! const term in beta
319  cb2 = cv0(2) ! coef for t term in beta
320  if (dabs(waa) .gt. zerotol) then
321  ! -- Case waa <> 0, wbb = 0
322  oowaa = 1d0 / waa
323  vfact = (wab * oowaa) * cv0(2)
324  ca1 = -oowaa * (cv0(1) + wab * beti + vfact) ! const term in alpha
325  ca2 = -vfact ! coef for t term in alpha
326  ca3 = alpi - ca1 ! coef for exp(waa*t) term in alpha
327  icase = 3
328  else
329  ! -- Case waa = 0, wbb = 0
330  ca1 = alpi ! const term in alpha
331  ca2 = cv0(1) + wab * beti ! coef for t term in alpha
332  ca3 = 5d-1 * wab * cv0(2) ! coef for t^2 term in alpha
333  icase = 4
334  end if
335  end if
336 
337  end subroutine
338 
339  !> @brief Step (evaluate) analytically depending on case
340  subroutine step_analytical(t, alp, bet)
341  ! -- dummy
342  real(dp), intent(in) :: t
343  real(dp) :: alp
344  real(dp) :: bet
345 
346  if (icase .eq. 1) then
347  alp = ca1 + ca2 * dexp(waa * t) + ca3 * dexp(wbb * t)
348  bet = cb1 + cb2 * dexp(wbb * t)
349  else if (icase .eq. -1) then
350  alp = ca1 + (ca2 + ca3 * t) * dexp(waa * t)
351  bet = cb1 + cb2 * dexp(wbb * t)
352  else if (icase .eq. 2) then
353  alp = ca1 + ca2 * t + ca3 * dexp(wbb * t)
354  bet = cb1 + cb2 * dexp(wbb * t)
355  else if (icase .eq. 3) then
356  alp = ca1 + ca2 * t + ca3 * dexp(waa * t)
357  bet = cb1 + cb2 * t
358  else if (icase .eq. 4) then
359  alp = ca1 + (ca2 + ca3 * t) * t
360  bet = cb1 + cb2 * t
361  end if
362 
363  end subroutine
364 
365  !> @brief Find the exit time and location in barycentric coordinates.
366  subroutine find_exit_bary(isolv, itriface, itrifaceenter, &
367  alpi, beti, &
368  tol, step, vziodz, az, &
369  texit, alpexit, betexit)
370  ! -- dummy
371  integer(I4B) :: isolv
372  integer(I4B) :: itriface
373  integer(I4B) :: itrifaceenter
374  real(dp) :: alpi
375  real(dp) :: beti
376  real(dp) :: tol
377  real(dp) :: step
378  real(dp) :: vziodz
379  real(dp) :: az
380  real(dp) :: texit
381  real(dp) :: alpexit
382  real(dp) :: betexit
383  ! -- local
384  real(dp) :: alplo
385  real(dp) :: alphi
386  real(dp) :: alpt
387  real(dp) :: alplim
388  real(dp) :: fax
389  real(dp) :: fbx
390  real(dp) :: t
391  real(dp) :: tlo
392  real(dp) :: thi
393  real(dp) :: v0alpstar
394  real(dp) :: valpi
395  real(dp) :: v1n
396  real(dp) :: v2n
397  real(dp) :: vbeti
398  real(dp) :: zerotol
399  real(dp) :: betlo
400  real(dp) :: bethi
401  real(dp) :: betsollo
402  real(dp) :: betsolhi
403  real(dp) :: betoutlo
404  real(dp) :: betouthi
405  integer(I4B) :: ibettrend
406 
407  ! -- Use iterative scheme or numerical integration indicated by isolv.
408  zerotol = 1d-10 ! kluge
409  if (itriface .eq. 0) then
410  ! -- Checking for exit on canonical face 0 (beta = 0)
411  if (itrifaceenter .eq. 0) then
412  ! -- Entrance face, so no exit. (Normal velocity is uniform along face 0,
413  ! -- so it cannot be both an entrance and an exit.)
414  texit = huge(1d0)
415  else
416  ! -- Not the entrance face, so check for outflow
417  if (cv0(2) .ge. 0d0) then
418  ! -- Inflow or no flow, so no exit
419  texit = huge(1d0)
420  else
421  ! -- Outflow, so check beta-velocity at the initial location,
422  ! -- recognizing that it will never change sign along the
423  ! -- trajectory (and will not be blocked from zero by an asymptote)
424  vbeti = cv0(2) + wbb * beti
425  if (vbeti .ge. 0d0) then
426  ! -- Can't exit along beta = 0
427  texit = huge(1d0)
428  else
429  ! -- get alpt and check it
430  call get_t_alpt(0d0, t, alpt)
431  if ((alpt .ge. 0d0) .and. (alpt .le. 1d0)) then
432  ! -- alpt within the edge, so exit found
433  texit = t
434  alpexit = alpt
435  betexit = 0d0
436  else
437  ! -- alpt not within the edge, so not an exit
438  texit = huge(1d0)
439  end if
440  end if
441  end if
442  end if
443  ! -- End canonical face 0 (beta = 0)
444  else
445  ! -- Checking for exit on canonical face 1 (gamma = 0.) or 2 (alpha = 0.)
446  if (itriface .eq. 1) then
447  ! -- Normal velocities (gamma components) at ends of canonical face 1
448  v1n = -cv1(1) - cv1(2)
449  v2n = -cv2(1) - cv2(2)
450  else
451  ! -- Normal velocities (alpha components) at ends of canonical face 2
452  v1n = cv0(1)
453  v2n = cv2(1)
454  end if
455  if ((v1n .ge. 0d0) .and. (v2n .ge. 0d0)) then
456  ! -- No outflow at vn1 and vn2 corners; no outflow interval, so no exit.
457  texit = huge(1d0)
458  else
459  ! -- Find outflow interval
460  call get_bet_outflow_bary(v1n, v2n, betoutlo, betouthi)
461  ! -- Find trend of and limits on beta from beta{t} solution
462  call get_bet_soln_limits(beti, betsollo, betsolhi, ibettrend)
463  ! -- Look for exit
464  if (ibettrend .eq. 0) then
465  ! -- Beta is constant, so check if it's within the outflow interval;
466  ! -- if not, no exit; if so, solve for t and alpha
467  if ((beti .gt. betouthi) .or. (beti .lt. betoutlo)) then
468  texit = huge(1d0)
469  else
470  ! -- Check alpha-velocity at the initial location,
471  ! -- recognizing that it will never change sign along the
472  ! -- trajectory (and will not be blocked from zero by an asymptote)
473  ! -- in this special case
474  v0alpstar = cv0(1) + wab * beti
475  valpi = v0alpstar + waa * alpi
476  if ((itriface .eq. 1) .and. (valpi .le. 0d0)) then
477  ! -- Can't exit along gamma = 0.
478  texit = huge(1d0)
479  else if ((itriface .eq. 2) .and. (valpi .ge. 0d0)) then
480  ! -- Can't exit along alpha = 0.
481  texit = huge(1d0)
482  else
483  ! -- get exit
484  if (itriface .eq. 1) then
485  alpexit = 1d0 - beti
486  else
487  alpexit = 0d0
488  end if ! kluge note: seems like in this case (beta=const) this
489  betexit = beti ! must be the ONLY exit; no need to check other edges??
490  if (waa .ne. 0d0) then
491  alplim = -v0alpstar / waa
492  texit = dlog(alpexit - alplim / (alpi - alplim)) / waa
493  else
494  texit = (alpexit - alpi) / v0alpstar
495  end if
496  end if
497  end if
498  ! -- End constant-beta case
499  else
500  ! -- Beta varies along trajectory; combine outflow and soln limits on beta
501  bethi = min(betouthi, betsolhi)
502  betlo = max(betoutlo, betsollo)
503  if (betlo .ge. bethi) then
504  ! -- If bounds on bet leave no feasible interval, no exit
505  texit = huge(1d0)
506  else
507  ! -- Check sign of function value at beta bounds
508  call get_t_alpt(bethi, thi, alphi)
509  call get_t_alpt(betlo, tlo, alplo)
510  if (itriface .eq. 1) then
511  fax = 1d0 - betlo - alplo
512  fbx = 1d0 - bethi - alphi
513  else
514  fax = alplo
515  fbx = alphi
516  end if
517  if (fax * fbx .gt. 0d0) then
518  ! -- Root not bracketed; no exit
519  texit = huge(1d0)
520  else
521  if (isolv .eq. 1) then
522  ! -- Use Brent's method with initial bounds on beta of betlo and bethi,
523  ! -- assuming they bound the root
524  call soln_brent(itriface, betlo, bethi, tol, texit, &
525  alpexit, betexit)
526  else if (isolv .eq. 2) then
527  ! -- Use Chandrupatla's method with initial bounds on beta of betlo and bethi,
528  ! -- assuming they bound the root
529  call soln_chand(itriface, betlo, bethi, tol, texit, &
530  alpexit, betexit)
531  else
532  call pstop(1, "Invalid isolv, expected one of: 1, 2")
533  end if
534  end if
535  end if
536  ! -- End variable-beta case
537  end if
538  end if
539  ! -- End canonical face 1 (gamma = 0.) or 2 (alpha = 0.)
540  end if
541 
542  if (texit .ne. huge(1d0) .and. texit .lt. 0d0) &
543  call pstop(1, "texit is negative (unexpected)") ! shouldn't get here
544 
545  end subroutine
546 
547  !> @brief Brent's method applied to canonical face 1 (gamma = 0)
548  function fbary1(bet) result(fb)
549  ! -- dummy
550  real(dp), intent(in) :: bet
551  real(dp) :: fb
552  ! -- local
553  real(dp) :: t
554  real(dp) :: alpt
555 
556  ! -- Evaluate gamma{t{beta}} = 1. - alpha{t{beta}} - beta
557  call get_t_alpt(bet, t, alpt)
558  fb = 1d0 - alpt - bet
559  end function
560 
561  !> @brief Brent's method applied to canonical face 2 (alpha = 0)
562  function fbary2(bet) result(fb)
563  ! -- dummy
564  real(dp), intent(in) :: bet
565  real(dp) :: fb
566  ! -- local
567  real(dp) :: t
568  real(dp) :: alpt
569 
570  ! -- Evaluate alpha{t{beta}}
571  call get_t_alpt(bet, t, alpt)
572  fb = alpt
573  end function
574 
575  !> @brief Given beta evaluate t and alpha depending on case
576  subroutine get_t_alpt(bet, t, alp)
577  ! -- dummy
578  real(dp), intent(in) :: bet
579  real(dp) :: t
580  real(dp) :: alp
581  ! -- local
582  real(dp) :: term
583  real(dp) :: zerotol
584 
585  ! kluge note: assumes cb2<>0, wbb<>0 as appropriate
586  zerotol = 1d-10 ! kluge
587  term = (bet - cb1) / cb2
588  if (icase .eq. 1) then
589  term = max(term, zerotol)
590  t = dlog(term) / wbb
591  alp = ca1 + ca2 * dexp(waa * t) + ca3 * dexp(wbb * t)
592  else if (icase .eq. -1) then
593  term = max(term, zerotol)
594  t = dlog(term) / wbb
595  alp = ca1 + (ca2 + ca3 * t) * dexp(waa * t)
596  else if (icase .eq. 2) then
597  term = max(term, zerotol)
598  t = dlog(term) / wbb
599  alp = ca1 + ca2 * t + ca3 * dexp(wbb * t)
600  else if (icase .eq. 3) then
601  t = term
602  alp = ca1 + ca2 * t + ca3 * dexp(waa * t)
603  else if (icase .eq. 4) then
604  t = term
605  alp = ca1 + (ca2 + ca3 * t) * t
606  end if
607 
608  end subroutine
609 
610  !> @brief Find outflow interval
611  subroutine get_bet_outflow_bary(vn1, vn2, betoutlo, betouthi)
612  ! -- dummy
613  real(dp) :: vn1
614  real(dp) :: vn2
615  real(dp) :: betoutlo
616  real(dp) :: betouthi
617  ! -- local
618  real(dp) :: vndiff
619 
620  vndiff = vn2 - vn1
621  if (vn1 .lt. 0d0) then
622  ! -- Outflow at vn1 corner
623  betoutlo = 0d0
624  if (vn2 .le. 0d0) then
625  ! -- Outflow along entire edge (except possibly no-flow right at vn2 corner)
626  betouthi = 1d0
627  else
628  ! -- Outflow along part of edge
629  betouthi = -vn1 / vndiff
630  end if
631  else
632  ! -- Outflow at vn2 corner
633  betouthi = 1d0
634  if (vn1 .le. 0d0) then
635  ! -- Outflow along entire edge (except possibly no-flow right at vn1 corner)
636  betoutlo = 0d0
637  else
638  ! -- Outflow along part of edge
639  betoutlo = -vn1 / vndiff
640  end if
641  end if
642 
643  end subroutine
644 
645  !> @brief Find trend of and limits on beta from beta{t} solution
646  subroutine get_bet_soln_limits(beti, betsollo, betsolhi, ibettrend)
647  ! -- dummy
648  real(dp), intent(in) :: beti
649  real(dp) :: betsollo
650  real(dp) :: betsolhi
651  integer(I4B), intent(inout) :: ibettrend
652  ! -- local
653  real(dp) :: betlim
654 
655  if (wbb .gt. 0d0) then
656  betlim = -cv0(2) / wbb
657  if (beti .gt. betlim) then
658  betsolhi = huge(1d0)
659  betsollo = beti
660  ibettrend = 1
661  else if (beti .lt. betlim) then
662  betsolhi = beti
663  betsollo = -huge(1d0)
664  ibettrend = -1
665  else
666  betsolhi = beti
667  betsollo = beti
668  ibettrend = 0
669  end if
670  else if (wbb .lt. 0d0) then
671  betlim = -cv0(2) / wbb
672  if (beti .gt. betlim) then
673  betsolhi = beti
674  betsollo = betlim
675  ibettrend = -1
676  else if (beti .lt. betlim) then
677  betsolhi = betlim
678  betsollo = beti
679  ibettrend = 1
680  else
681  betsolhi = beti
682  betsollo = beti
683  ibettrend = 0
684  end if
685  else ! kluge note: use zerotol and elsewhere?
686  if (cv0(2) .gt. 0d0) then
687  betsolhi = huge(1d0)
688  betsollo = beti
689  ibettrend = 1
690  else if (cv0(2) .lt. 0d0) then
691  betsolhi = beti
692  betsollo = -huge(1d0)
693  ibettrend = -1
694  else
695  betsolhi = beti
696  betsollo = beti
697  ibettrend = 0
698  end if
699  end if
700 
701  end subroutine
702 
703  !> @brief Use Brent's method with initial bounds on beta of betlo and bethi
704  subroutine soln_brent(itriface, betlo, bethi, tol, &
705  texit, alpexit, betexit)
706  ! -- dummy
707  integer(I4B), intent(in) :: itriface
708  real(dp) :: betlo
709  real(dp) :: bethi
710  real(dp), intent(in) :: tol
711  real(dp) :: texit
712  real(dp) :: alpexit
713  real(dp) :: betexit
714  ! -- local
715  real(dp) :: itmax
716  real(dp) :: itact
717  real(dp) :: blo
718  real(dp) :: bhi
719  procedure(f1d), pointer :: f
720 
721  ! -- assuming betlo and bethi bracket the root
722  ! --
723  ! tol = 1d-7 ! kluge
724  itmax = 50 ! kluge
725  itact = itmax + 1 ! kluge
726  blo = betlo
727  bhi = bethi
728  if (itriface .eq. 1) then
729  f => fbary1
730  betexit = zero_br(blo, bhi, f, tol)
731  else
732  f => fbary2
733  betexit = zero_br(blo, bhi, f, tol)
734  end if
735  call get_t_alpt(betexit, texit, alpexit)
736 
737  end subroutine
738 
739  !> @brief Use Chandrupatla's method with initial bounds on beta of betlo and bethi
740  subroutine soln_chand(itriface, betlo, bethi, tol, &
741  texit, alpexit, betexit)
742  ! -- dummy
743  integer(I4B), intent(in) :: itriface
744  real(dp) :: betlo
745  real(dp) :: bethi
746  real(dp), intent(in) :: tol
747  real(dp) :: texit
748  real(dp) :: alpexit
749  real(dp) :: betexit
750  ! -- local
751  real(dp) :: itmax
752  real(dp) :: itact
753  real(dp) :: blo
754  real(dp) :: bhi
755  procedure(f1d), pointer :: f
756 
757  ! -- note: assuming betlo and bethi bracket the root
758  ! tol = 1d-7 ! kluge
759  itmax = 50 ! kluge
760  itact = itmax + 1 ! kluge
761  blo = betlo
762  bhi = bethi
763  if (itriface .eq. 1) then
764  f => fbary1
765  betexit = zero_ch(blo, bhi, f, tol)
766  else
767  f => fbary2
768  betexit = zero_ch(blo, bhi, f, tol)
769  end if
770  call get_t_alpt(betexit, texit, alpexit)
771 
772  end subroutine
773 
774 end module ternarysolvetrack
subroutine pstop(status, message)
Stop the program, optionally specifying an error status code.
Definition: ErrorUtil.f90:24
pure real(dp) function, dimension(2), public skew(v, s, invert)
Skew a 2D vector along the x-axis.
Definition: GeomUtil.f90:147
This module defines variable data types.
Definition: kind.f90:8
real(dp) function, public zero_ch(x0, x1, f, epsa)
Compute zeros on an interval using Chadrupatla's method.
Definition: MathUtil.f90:133
real(dp) function, public zero_br(ax, bx, f, tol)
Compute a zero of the function f(x) in the interval (x0, x1).
Definition: MathUtil.f90:251
real(dp) function fbary1(bet)
Brent's method applied to canonical face 1 (gamma = 0)
subroutine, public traverse_triangle(isolv, tol, step, texit, alpexit, betexit, itrifaceenter, itrifaceexit, rxx, rxy, ryx, ryy, alp0, bet0, alp1, bet1, alp2, bet2, alpi, beti, vziodz, az, bary)
Traverse triangular cell.
real(dp), dimension(2) cv2
"Canonical" velocity components at corners of triangular subcell
integer(i4b) icase
Case index for analytical solution.
subroutine, public find_exit_bary(isolv, itriface, itrifaceenter, alpi, beti, tol, step, vziodz, az, texit, alpexit, betexit)
Find the exit time and location in barycentric coordinates.
real(dp) wbb
Elements of the "velocity matrix," W.
subroutine, public get_w(alp1, bet1, alp2, bet2, waa, wab, wba, wbb, bary)
Compute elements of W matrix.
real(dp), dimension(2) cv1
subroutine, public get_bet_outflow_bary(vn1, vn2, betoutlo, betouthi)
Find outflow interval.
subroutine, public get_t_alpt(bet, t, alp)
Given beta evaluate t and alpha depending on case.
subroutine, public get_bet_soln_limits(beti, betsollo, betsolhi, ibettrend)
Find trend of and limits on beta from beta{t} solution.
subroutine, public solve_coefs(alpi, beti)
Compute analytical solution coefficients depending on case.
subroutine, public soln_brent(itriface, betlo, bethi, tol, texit, alpexit, betexit)
Use Brent's method with initial bounds on beta of betlo and bethi.
real(dp) cb2
Analytical solution coefficients.
real(dp), dimension(2) cv0
real(dp) function fbary2(bet)
Brent's method applied to canonical face 2 (alpha = 0)
subroutine, public canonical(x0, y0, x1, y1, x2, y2, v0x, v0y, v1x, v1y, v2x, v2y, xi, yi, rxx, rxy, ryx, ryy, sxx, sxy, syy, alp0, bet0, alp1, bet1, alp2, bet2, alpi, beti, bary)
Set coordinates to "canonical" configuration.
subroutine, public soln_chand(itriface, betlo, bethi, tol, texit, alpexit, betexit)
Use Chandrupatla's method with initial bounds on beta of betlo and bethi.
subroutine, public step_analytical(t, alp, bet)
Step (evaluate) analytically depending on case.