2 ! Author(s)/Contact(s):
7 ! Parameters: <Specify typical arguments passed>
9 ! <list file names and briefly describe the data they include>
11 ! <list file names and briefly describe the information they include>
14 ! <list exit condition or error codes returned >
15 ! If appropriate, descriptive troubleshooting instructions or
16 ! likely causes for failures could be mentioned here with the
17 ! appropriate error code
19 ! User controllable options: <if applicable>
21 !------------------------------------------------------------------------------
22 ! Benjamin Fersch 2d groundwater model
23 !------------------------------------------------------------------------------
32 use module_gw_gw2d_data, only: gw2d
33 use module_rt_data, only: rt_domain
34 use config_base, only: nlst
38 #include "gw_field_include.inc"
42 integer, private :: ierr
43 integer, parameter :: rowshift = 0
44 integer, parameter :: colshift = 1
51 subroutine gw2d_ini(did,dt,dx)
53 use module_HYDRO_io, only: output_gw_spinup
58 integer :: jj, ii, iter, itermax
63 itermax = nlst(did)%GwPreCycles
67 gw2d(did)%qgw_chanrt = 0.
69 gw2d(did)%qdarcyRT = 0.
72 gw2d(did)%compres=0. ! currently not implemented
73 gw2d(did)%istep=0 ! initialize time step
74 ! reset cells with undefined hydraulic conductivity
75 where(gw2d(did)%hycond .eq. 100) gw2d(did)%hycond = 5E-4
80 if(my_id .eq. IO_id) &
82 write(6,*) " GW Pre-cycle", iter, "of", itermax
84 call gwstep(gw2d(did)%ix, gw2d(did)%jx, gw2d(did)%dx, &
85 gw2d(did)%ltype, gw2d(did)%elev, gw2d(did)%bot, &
86 gw2d(did)%hycond, gw2d(did)%poros, gw2d(did)%compres, &
87 gw2d(did)%ho, gw2d(did)%h, gw2d(did)%convgw, gw2d(did)%excess, &
88 gw2d(did)%ebot, gw2d(did)%eocn, gw2d(did)%dt, &
91 gw2d(did)%ho = gw2d(did)%h
93 if((nlst(did)%GwPreDiag .and. iter==1) .or. &
94 nlst(did)%GwPreDiag .and. (mod(iter, nlst(did)%GwPreDiagInterval) .eq. 0) ) then
95 call output_gw_spinup(nlst(did)%igrid, 1000000, &
96 RT_DOMAIN(did)%ixrt, RT_DOMAIN(did)%jxrt, &
97 nlst(did)%startdate, nlst(did)%olddate, &
98 gw2d(did)%ho, gw2d(did)%convgw, gw2d(did)%excess, &
99 nlst(did)%geo_finegrid_flnm,nlst(did)%DT, &
100 RT_DOMAIN(did)%LATVAL, &
101 RT_DOMAIN(did)%LONVAL,rt_domain(did)%overland%properties%distance_to_neighbor, &
109 end subroutine gw2d_ini
111 subroutine gw2d_allocate(did, ix, jx, nsoil)
114 integer ix, jx, nsoil
117 if(gw2d(did)%allo_status .eq. 1) return
118 gw2d(did)%allo_status = 1
124 if(down_id == -1) then ! if south border
130 if(up_id == -1) then !if north border
136 if(left_id == -1) then !if west border
142 if(right_id == -1) then ! if east border
155 allocate(gw2d(did)%ltype (ix,jx))
156 allocate(gw2d(did)%elev (ix,jx))
157 allocate(gw2d(did)%bot (ix,jx))
158 allocate(gw2d(did)%hycond (ix,jx))
159 allocate(gw2d(did)%poros (ix,jx))
160 allocate(gw2d(did)%compres(ix,jx))
161 allocate(gw2d(did)%ho (ix,jx))
162 allocate(gw2d(did)%h (ix,jx))
163 allocate(gw2d(did)%convgw (ix,jx))
164 allocate(gw2d(did)%excess (ix,jx))
166 allocate(gw2d(did)%qgw_chanrt (ix,jx))
169 ! TODO allocate only if gwSoilCoupling is active
170 allocate(gw2d(did)%qsgwrt (ix,jx))
171 allocate(gw2d(did)%qsgw (rt_domain(did)%ix,rt_domain(did)%jx))
172 allocate(gw2d(did)%qdarcyRT (ix,jx))
174 end subroutine gw2d_allocate
177 subroutine gwstep(ix, jx, dx, &
179 hycond, poros, compres, &
180 ho, h, convgw, excess, &
184 ! New (volug): calling routines use change in head, convgw = d(h-ho)/dt.
186 ! Steps ground-water hydrology (head) through one timestep.
187 ! Modified from Prickett and Lonnquist (1971), basic one-layer aquifer
188 ! simulation program, with mods by Zhongbo Yu(1997).
189 ! Solves S.dh/dt = d/dx(T.dh/dx) + d/dy(T.dh/dy) + "external sources"
190 ! for a single layer, where h is head, S is storage coeff and T is
191 ! transmissivity. 3-D arrays in main program (hycond,poros,h,bot)
192 ! are 2-D here, since only a single (uppermost) layer is solved.
193 ! Uses an iterative time-implicit ADI method.
195 ! use module_hms_constants
199 integer, intent(in) :: ix, jx
201 integer, intent(in), dimension(ix,jx) :: ltype ! land-sfc type (supp)
202 real, intent(in), dimension(ix,jx) :: &
203 elev, & ! elev/bathymetry of sfc rel to sl (m) (supp)
204 bot, & ! elev. aquifer bottom rel to sl (m) (supp)
205 hycond, & ! hydraulic conductivity (m/s per m/m) (supp)
206 poros, & ! porosity (m3/m3) (supp)
207 compres, & ! compressibility (1/Pa) (supp)
208 ho ! head at start of timestep (m) (supp)
210 real, intent(inout), dimension(ix,jx) :: &
211 h, & ! head, after ghmcompute (m) (ret)
212 convgw, & ! convergence due to gw flow (m/s) (ret)
215 real, intent(inout) :: ebot, eocn
219 integer :: istep !, dt
220 real, intent(in) :: dt, dx
223 ! eocn = mean spurious sink for h_ocn = sealev fix (m/s)(ret)
224 ! This equals the total ground-water flow across
225 ! land->ocean boundaries.
226 ! ebot = mean spurious source for "bot" fix (m/s) (returned)
227 ! time = elapsed time from start of run (sec)
228 ! dt = timestep length (sec)
229 ! istep = timestep counter
233 real, dimension(ix,jx) :: sf2 ! storage coefficient (m3 of h2o / bulk m3)
234 real, dimension(ix,jx,2) :: t ! transmissivity (m2/s)..1 for N-S,..2 for E-W
237 real, dimension(:,:), allocatable :: aa, & ! tridiagonal matrix lower diagonal
238 bb, & ! tridiagonal matrix main diagonal
239 cc, & ! tridiagonal matrix upper diagonal
240 dd, & ! right hand side
246 real, dimension(:), allocatable :: xfac, &
249 real, dimension(:), allocatable :: aa, & ! tridiagonal matrix lower diagonal
250 bb, & ! tridiagonal matrix main diagonal
251 cc, & ! tridiagonal matrix upper diagonal
252 dd, & ! right hand side
255 real, parameter :: botinc = 0.01 ! re-wetting increment to fix h < bot
256 ! parameter (botinc = 0. ) ! re-wetting increment to fix h < bot
257 ! (m); else no flow into dry cells
258 real, parameter :: delskip = 0.005 ! av.|dhead| value for iter.skip out(m)
259 integer, parameter :: itermax = 1 ! maximum number of iterations
260 integer, parameter :: itermin = 1 ! minimum number of iterations
261 real, parameter :: sealev = 1000. ! sea-level elevation (m)
263 integer :: its, ite, jts, jte, ifs, ife, jfs, jfe, &
264 xdim, ydim, fxdim, fydim
266 ! die müssen noch sortiert, geprüft und aufgeräumt werden
279 ! real :: su, sc, shp, bb, aa, cc, w, zz, tareal, dtoa, dtot
309 ! define indexes for parallel execution
312 if(down_id == -1) then ! if south border
318 if(up_id == -1) then !if north border
324 if(left_id == -1) then !if west border
330 if(right_id == -1) then ! if east border
355 call scopy (fxdim*fydim, ho(ifs:ife,jfs:jfe), 1, &
356 h(ifs:ife,jfs:jfe), 1)
359 ! Top of iterative loop for (not anymore ADI) solution
370 call MPP_LAND_COM_REAL(h, fxdim, fydim, 99)
373 e = 0. ! absolute changes in head (for iteration control)
374 ! eocn = 0. ! accumulated fixes for h = 0 over ocean (diag)
375 ! ebot = 0. ! accumulated fixes for h < bot (diagnostic)
377 ! Set storage coefficient (sf2)
386 if(ltype(i,j) .ge. 1) tareal = tareal + darea
388 ! unconfined water table (h < e): V = poros*(h-b)
390 ! saturated to surface (h >= e) : V = poros*(e-b) + (h-e)
392 ! (compressibility is ignored)
394 ! su = poros(i,j)*(1.-theta(i,j)) ! old (pre-volug)
395 su = poros(i,j) ! new (volug)
398 ! if (ho(i,j).le.elev(i,j) .and. h(i,j).le.elev(i,j)) then
400 ! else if (ho(i,j).ge.elev(i,j) .and. h(i,j).ge.elev(i,j)) then
402 ! else if (ho(i,j).le.elev(i,j) .and. h(i,j).ge.elev(i,j)) then
403 ! shp = sf2(i,j) * (h(i,j) - ho(i,j))
404 ! sf2(i,j) = shp * sc / (shp - (su-sc)*(elev(i,j)-ho(i,j)))
405 ! else if (ho(i,j).ge.elev(i,j) .and. h(i,j).le.elev(i,j)) then
406 ! shp = sf2(i,j) * (ho(i,j) - h(i,j))
407 ! sf2(i,j) = shp * su / (shp + (su-sc)*(ho(i,j)-elev(i,j)))
414 ! communicate storage coefficient
415 call MPP_LAND_COM_REAL(sf2, fxdim, fydim, 99)
419 !==========================
420 ! Column calculations
421 !==========================
423 ! Set transmissivities. Use min(h,elev)-bot instead of h-bot,
424 ! since if h > elev, thickness of groundwater flow is just
425 ! elev-bot. (uses geometric mean)
433 t(i,j,2) = sqrt( abs( &
434 hycond(i, j)*(min(h(i ,j),elev(i ,j))-bot(i ,j)) &
435 *hycond(ip,j)*(min(h(ip,j),elev(ip,j))-bot(ip,j)) &
437 * (0.5*(dy+dy)) & ! in WRF the dx and dy are usually equal
440 t(i,j,1) = sqrt( abs( &
441 hycond(i,j )*(min(h(i,j ),elev(i,j ))-bot(i,j )) &
442 *hycond(i,jp)*(min(h(i,jp),elev(i,jp))-bot(i,jp)) &
456 ! communicate transmissivities in x and y direction
457 call MPP_LAND_COM_REAL(t(:,:,1), fxdim, fydim, 99)
458 call MPP_LAND_COM_REAL(t(:,:,2), fxdim, fydim, 99)
461 allocate(aa(jts:jte,its:ite))
462 allocate(bb(jts:jte,its:ite))
463 allocate(cc(jts:jte,its:ite))
464 allocate(dd(jts:jte,its:ite))
465 allocate(c2(1:ydim,1:xdim))
466 allocate(b2(1:ydim,1:xdim))
467 allocate(wk(1:ydim,1:xdim))
468 allocate(hh(0:ydim+1,0:xdim+1))
469 allocate(xfac(1:ydim))
470 allocate(zfac(1:ydim))
472 allocate(aa(jfs:jfe))
473 allocate(bb(jfs:jfe))
474 allocate(cc(jfs:jfe))
475 allocate(dd(jfs:jfe))
476 allocate(hh(jfs:jfe))
482 !>>>>>>>>>>>>>>>>>>>>
484 !>>>>>>>>>>>>>>>>>>>>
487 bb(j) = (sf2(i,j)/dt) * darea
488 dd(j) = ( ho(i,j)*sf2(i,j)/dt ) * darea
492 if ((j-jfs) /= 0) then
494 bb(j) = bb(j) + t(i,j-1,1)
497 if ((j-jfe) /= 0) then
499 bb(j) = bb(j) + t(i,j,1)
502 if ((i-ifs) /= 0) then
503 bb(j) = bb(j) + t(i-1,j,2)
504 dd(j) = dd(j) + h(i-1,j)*t(i-1,j,2)
507 if ((i-ife) /= 0) then
508 bb(j) = bb(j) + t(i,j,2)
509 dd(j) = dd(j) + h(i+1,j)*t(i,j,2)
516 call trdiagSolve(aa, bb, cc, dd, hh, fydim)
532 !>>>>>>>>>>>>>>>>>>>>
534 !>>>>>>>>>>>>>>>>>>>>
535 bb(j,i) = (sf2(i,j)/dt) * darea
536 dd(j,i) = ( ho(i,j)*sf2(i,j)/dt ) * darea
540 if (((j-jfs) /= 0)) then
541 aa(j,i) = -t(i,j-1,1)
542 bb(j,i) = bb(j,i) + t(i,j-1,1)
545 if (((j-jfe) /= 0)) then
547 bb(j,i) = bb(j,i) + t(i,j,1)
550 if (((i-ifs) /= 0)) then
551 bb(j,i) = bb(j,i) + t(i-1,j,2)
552 dd(j,i) = dd(j,i) + h(i-1,j)*t(i-1,j,2)
555 if (((i-ife) /= 0)) then
556 bb(j,i) = bb(j,i) + t(i,j,2)
557 dd(j,i) = dd(j,i) + h(i+1,j)*t(i,j,2)
568 if(np_up_down .gt. 1) then
569 call sub_n_form(xdim, ydim, aa, &
572 c2, b2, hh, wk, xfac, zfac, &
573 p_up_down+1, np_up_down, 2)
576 call parysolv1(c2, b2, hh, 1., my_id+1, p_up_down+1, &
577 xdim, ydim, np_left_right, np_up_down)
580 call sub_tri_solv(xdim,ydim,aa(jts:jte,its:ite), &
581 bb(jts:jte,its:ite), cc(jts:jte,its:ite), &
582 dd(jts:jte,its:ite), &
592 !>>>>>>>>>>>>>>>>>>>>
594 !>>>>>>>>>>>>>>>>>>>>
596 h(i,j) = hh(j-joffs,i-ioffs)
605 call MPP_LAND_COM_REAL(h, fxdim, fydim, 99)
610 !=======================
612 !=======================
614 ! set transmissivities (same as above)
621 t(i,j,2) = sqrt( abs( &
622 hycond(i, j)*(min(h(i ,j),elev(i ,j))-bot(i ,j)) &
623 *hycond(ip,j)*(min(h(ip,j),elev(ip,j))-bot(ip,j)) &
628 t(i,j,1) = sqrt( abs( &
629 hycond(i,j )*(min(h(i,j ),elev(i,j ))-bot(i,j )) &
630 *hycond(i,jp)*(min(h(i,jp),elev(i,jp))-bot(i,jp)) &
640 ! communicate transmissivities in x and y direction
641 call MPP_LAND_COM_REAL(t(:,:,1), fxdim, fydim, 99)
642 call MPP_LAND_COM_REAL(t(:,:,2), fxdim, fydim, 99)
646 allocate(aa(ifs:ife))
647 allocate(bb(ifs:ife))
648 allocate(cc(ifs:ife))
649 allocate(dd(ifs:ife))
650 allocate(hh(ifs:ife))
658 !>>>>>>>>>>>>>>>>>>>>
660 !>>>>>>>>>>>>>>>>>>>>
661 bb(i) = (sf2(i,j)/dt) * darea
662 dd(i) = ( ho(i,j)*sf2(i,j)/dt ) * darea
666 if ((j-jfs) /= 0) then
667 bb(i) = bb(i) + t(i,j-1,1)
668 dd(i) = dd(i) + h(i,j-1)*t(i,j-1,1)
671 if ((j-jfe) /= 0) then
672 dd(i) = dd(i) + h(i,j+1)*t(i,j,1)
673 bb(i) = bb(i) + t(i,j,1)
676 if ((i-ifs) /= 0) then
677 bb(i) = bb(i) + t(i-1,j,2)
681 if ((i-ife) /= 0) then
682 bb(i) = bb(i) + t(i,j,2)
690 call trdiagSolve(aa, bb, cc, dd, hh, fxdim)
700 !>>>>>>>>>>>>>>>>>>>>
702 !>>>>>>>>>>>>>>>>>>>>
703 bb(j,i) = (sf2(i,j)/dt) * darea
704 dd(j,i) = ( ho(i,j)*sf2(i,j)/dt ) * darea
708 if (((j-jfs) /= 0)) then
709 bb(j,i) = bb(j,i) + t(i,j-1,1)
710 dd(j,i) = dd(j,i) + h(i,j-1)*t(i,j-1,1)
713 if (((j-jfe) /= 0)) then
714 dd(j,i) = dd(j,i) + h(i,j+1)*t(i,j,1)
715 bb(j,i) = bb(j,i) + t(i,j,1)
718 if (((i-ifs) /= 0)) then
719 bb(j,i) = bb(j,i) + t(i-1,j,2)
720 aa(j,i) = -t(i-1,j,2)
723 if (((i-ife) /= 0)) then
724 bb(j,i) = bb(j,i) + t(i,j,2)
736 if(np_left_right .gt. 1) then
738 ! 3 c(,) -- subdiagonal elements of tridiagonal systems
739 ! 4 a(,) -- diagonal elements of tridiagonal systems
740 ! 5 b(,) -- superdiagonal elements of tridiagonal systems
741 ! 6 r(,) -- right-hand side elements of tridiagonal systems
742 ! 7 c2(,) -- front-leg elements of N-systems
743 ! 8 b2(,) -- back-leg elements of N-systems
744 ! 9 r2(,) -- right-hand side elements of N-systems (0:ydim+1,0:xdim+1)
745 ! 10 wk(,) -- work array with same dimensions as a, b, c, etc.
747 call sub_n_form(xdim, ydim, aa, &
750 c2, b2, hh, wk, xfac, zfac, &
751 p_left_right+1, np_left_right, 1)
753 call parxsolv1(c2, b2, hh, 1., my_id+1, p_left_right+1, &
754 xdim, ydim, np_left_right, np_up_down)
757 call sub_tri_solv(xdim,ydim,aa, &
768 !>>>>>>>>>>>>>>>>>>>>
770 !>>>>>>>>>>>>>>>>>>>>
772 h(i,j) = hh(j-joffs,i-ioffs)
789 ! fix head < bottom of aquifer
793 if (ltype(i,j).eq.1 .and. h(i,j).le.bot(i,j)+botinc) then
795 e = e + bot(i,j) + botinc - h(i,j)
796 ! ebot = ebot + (bot(i,j)+botinc-h(i,j))*sf2(i,j)*darea(i,j)
797 ebot = ebot + (bot(i,j)+botinc-h(i,j))*sf2(i,j)*darea
799 h(i,j) = bot(i,j) + botinc
803 ! maintain head = sea level for ocean (only for adjacent ocean,
808 if (ltype(i,j).eq.2) then
810 eocn = eocn + (h(i,j)-sealev)*sf2(i,j)*darea
811 ! eocn = eocn + (h(i,j)-sealev)*sf2(i,j)*darea(i,j)
813 ! h(i,j) = sealev (no update of outer boundary cells)
818 ! Loop back for next ADI iteration
820 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
821 delcur = e/(xdim*ydim)
823 ! print*, 'delcur before mpi:', delcur
827 call mpi_reduce(delcur, mpiDelcur, 1, MPI_REAL, MPI_SUM, 0, HYDRO_COMM_WORLD, ierr)
828 call MPI_COMM_SIZE( HYDRO_COMM_WORLD, mpiSize, ierr )
830 if(my_id .eq. IO_id) delcur = mpiDelcur/mpiSize
832 call mpi_bcast(delcur, 1, mpi_real, 0, HYDRO_COMM_WORLD, ierr)
836 ! if ( (delcur.gt.delskip*dt/86400. .and. iter.lt.itermax) &
837 if ( (delcur.gt.delskip .and. iter.lt.itermax) &
838 .or. iter.lt.itermin ) then
843 if(my_id .eq. IO_id) write(6,*) "Iteration", iter, "of", itermax, "error:", delcur
845 write(6,*) "Iteration", iter, "of", itermax, "error:", delcur
855 call MPP_LAND_COM_REAL(h, fxdim, fydim, 99)
861 ! Compute exfiltration amount and
862 ! convergence rate due to ground water
868 if((elev(i,j) - h(i,j)) .lt. 0.) then
869 excess(i,j) = sf2(i,j)*(h(i,j) - elev(i,j))
875 if(ltype(i,j).eq.1) then
876 convgw(i,j) = sf2(i,j) * (h(i,j)-ho(i,j)) / dt
883 ! call MPP_LAND_COM_REAL(convgw, fxdim, fydim, 99)
885 ! Diagnostic water conservation check for this timestep
887 dtot = 0. ! total change in water storage (m3)
892 if (ltype(i,j).eq.1) then
894 dtot = dtot + sf2(i,j) *(h(i,j)-ho(i,j)) * darea
895 dtoa = dtoa + sf2(i,j) * abs(h(i,j)-ho(i,j)) * darea
897 ! dtot = dtot + sf2(i,j) *(h(i,j)-ho(i,j)) * darea(i,j)
898 ! dtoa = dtoa + sf2(i,j) * abs(h(i,j)-ho(i,j)) * darea(i,j)
903 dtot = (dtot/tareal)/dt ! convert to m/s, rel to land area
904 dtoa = (dtoa/tareal)/dt
905 eocn = (eocn/tareal)/dt
906 ebot = (ebot/tareal)/dt
908 zz = 1.e3 * 86400. ! convert printout to mm/day
912 call MPI_REDUCE(dtot,gdtot,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
913 call MPI_REDUCE(dtoa,gdtoa,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
914 call MPI_REDUCE(eocn,geocn,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
915 call MPI_REDUCE(ebot,gebot,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
917 if(my_id .eq. IO_id) then
919 gdtot*zz, gdtoa*zz, -geocn*zz, gebot*zz, &
920 (gdtot-(-geocn+gebot))*zz
926 dtot*zz, dtoa*zz, -eocn*zz, ebot*zz, &
927 (dtot-(-eocn+ebot))*zz
931 (3x,' dh/dt |dh/dt| ocnflx botfix',&
933 ! /3x,4f9.4,2(9x),e14.4)
937 end subroutine gwstep
940 SUBROUTINE SCOPY (NT, ARR, INCA, BRR, INCB)
942 ! Copies array ARR to BRR, incrementing by INCA and INCB
943 ! respectively, up to a total length of NT words of ARR.
944 ! (Same as Cray SCOPY.)
946 real, DIMENSION(*) :: ARR, BRR
947 integer :: ia, nt, inca, incb, ib
959 subroutine trdiagSolve(a,b,c,rhs,x,n)
963 integer,intent(in) :: n
964 real,dimension(n),intent(in) :: a, b, c, rhs
965 real,dimension(n),intent(out) :: x
966 real,dimension(n) :: cp, dp
970 ! initialize c-prime and d-prime
973 ! solve for vectors c-prime and d-prime
975 m = b(i)-cp(i-1)*a(i)
977 dp(i) = (rhs(i)-dp(i-1)*a(i))/m
981 ! solve for x from the vectors c-prime and d-prime
983 x(i) = dp(i)-cp(i)*x(i+1)
987 end subroutine trdiagSolve
990 subroutine gwSoilFlux(did)
995 integer, intent(in) :: did
998 real, dimension(rt_domain(did)%ixrt,rt_domain(did)%jxrt) :: smcrel, ztrans, headChange
1000 integer :: nsoil, i, j, k
1002 gw2d(did)%qsgwrt = 0.
1003 gw2d(did)%qdarcyRT = 0.
1005 ! Step 1, collect data
1007 ! relative soil moisture content of lowest soil layer (1 = saturated)
1008 nsoil = nlst(did)%nsoil
1009 smcrel = rt_domain(did)%subsurface%grid_transform%smcrt(:,:,nsoil) / RT_DOMAIN(did)%subsurface%grid_transform%smcmaxrt(:,:,nsoil)
1011 ! depth of transition zone from lowest soil layer to groundwater head (in cm)
1012 ! postivie ztrans -> head below LSM soil layer
1013 ! negative ztrans -> head within LSM soil layers
1014 ztrans = (rt_domain(did)%elrt + nlst(did)%zsoil8(nsoil)) - gw2d(did)%ho
1015 ztrans = ztrans * 100
1017 ! darcyGwSoil not defined for ztran = 0
1018 where(ztrans == 0) ztrans = -5
1020 ! Step 2, compute flux either up or down
1022 do j=gw2d(did)%jts, gw2d(did)%jte
1023 do i=gw2d(did)%its, gw2d(did)%ite
1025 if((ztrans(i,j) > 0) .and. (rt_domain(did)%soiltypRT(i,j) < 13)) then
1026 ! if groundwater head < soil layers
1027 call darcyGwSoil(ztrans(i,j), smcrel(i,j), rt_domain(did)%soiltypRT(i,j), gw2d(did)%qdarcyRT(i,j))
1029 gw2d(did)%qsgwrt(i,j) = gw2d(did)%qdarcyRT(i,j)
1031 ! check and correct for mass balance
1032 if(((gw2d(did)%ho(i,j)-gw2d(did)%bot(i,j)) &
1033 *gw2d(did)%poros(i,j)) < (gw2d(did)%qsgwrt(i,j)*gw2d(did)%dt)) then
1035 gw2d(did)%qdarcyRT(i,j) = 0.
1036 gw2d(did)%qsgwrt(i,j) = 0.
1040 else if(ztrans(i,j) < 0 .and. (rt_domain(did)%soiltypRT(i,j) < 13)) then
1041 ! if groundwater head > soil layers
1045 if(zres >= rt_domain(did)%subsurface%properties%sldpth(k)*100.) then
1046 ! complete filling of a LSM soil layer if groundwater head > layer top
1048 ! gw2d(did)%qsgwrt(i,j) = (rt_domain(did)%subsurface%properties%sldpth(k) &
1049 ! * (rt_domain(did)%subsurface%grid_transform%smcmaxrt(i,j,k) - RT_DOMAIN(did)%subsurface%grid_transform%smcrt(i,j,k)) &
1050 ! + gw2d(did)%qsgwrt(i,j)) / gw2d(did)%dt
1052 rt_domain(did)%subsurface%grid_transform%smcrt(i,j,k) = RT_DOMAIN(did)%subsurface%grid_transform%smcmaxrt(i,j,k)
1054 zres = zres - rt_domain(did)%subsurface%properties%sldpth(k)*100.
1057 ! partial filling of a soil layer if not completely below groundwater head
1059 if(zres > (0.5 * rt_domain(did)%subsurface%properties%sldpth(k)*100.)) then
1061 frac = zres / (rt_domain(did)%subsurface%properties%sldpth(k) * 100.)
1064 ! gw2d(did)%qsgwrt(i,j) = (rt_domain(did)%subsurface%properties%sldpth(k) &
1065 ! * (rt_domain(did)%subsurface%grid_transform%smcmaxrt(i,j,k) - RT_DOMAIN(did)%subsurface%grid_transform%smcrt(i,j,k)) &
1066 ! * frac + gw2d(did)%qsgwrt(i,j)) / gw2d(did)%dt
1068 rt_domain(did)%subsurface%grid_transform%smcrt(i,j,k) = RT_DOMAIN(did)%subsurface%grid_transform%smcmaxrt(i,j,k) * frac
1079 ! qsgwrt < 0 -> downward flux
1080 ! qsgwrt > 0 -> upward flux
1082 ! TOcheck Step 3, adapt groundwater head (assuming not time lag for percolation / capillary rise flow)
1084 ! modify gw-head before gwstep call with respect to specific yield of the
1085 ! aquifer and the computed flux (qsgwrt)
1088 headChange = (-gw2d(did)%qdarcyRT) * gw2d(did)%dt / gw2d(did)%poros
1089 gw2d(did)%ho = gw2d(did)%ho + headChange
1091 end subroutine gwSoilFlux
1093 subroutine darcyGwSoil(Z, s, soil, q_darcy)
1097 INTEGER, INTENT (IN) :: soil ! soiltype
1099 REAL :: sig_a, sig_b, sig_c
1101 REAL, DIMENSION(9) :: k_para
1102 REAL, INTENT (IN) :: Z, s
1103 REAL, INTENT (OUT) :: q_darcy
1104 real :: beta,alpha,q_cap,b,ks,aep,c,q_grav,y,fac
1106 real, dimension(9,12) :: &
1107 k_soil = reshape((/&
1108 0.0778, 3.9939, 0.2913, 4.0801, 0.1386, 4.0500, -12.10, 0.3950, 1.0560,&
1109 0.0924, 4.8822, 0.2674, 3.8915, 0.1365, 4.3800, -09.00, 0.4100, 0.9380,&
1110 0.0367, 4.5259, 0.2446, 4.2849, 0.1208, 4.9000, -21.80, 0.4350, 0.2080,&
1111 0.0101, 3.6896, 0.2153, 4.2765, 0.0887, 5.3000, -78.60, 0.4850, 0.0432,&
1112 0.0101, 3.6896, 0.2153, 4.2765, 0.0887, 5.3000, -78.60, 0.4850, 0.0432,&
1113 0.0169, 2.9936, 0.2858, 4.3738, 0.1026, 5.3900, -47.80, 0.4510, 0.0417,&
1114 0.0271, 4.4743, 0.2587, 3.9055, 0.0920, 7.1200, -29.90, 0.4200, 0.0378,&
1115 0.0227, 4.3768, 0.2658, 3.8234, 0.0843, 7.7500, -35.60, 0.4770, 0.0102,&
1116 0.0127, 6.6836, 0.1725, 3.7512, 0.0703, 8.5200, -63.00, 0.4760, 0.0147,&
1117 0.0530, 9.2423, 0.1859, 3.3688, 0.0728, 10.400, -15.30, 0.4260, 0.0130,&
1118 0.0165, 5.3972, 0.2479, 3.5549, 0.0641, 10.400, -49.00, 0.4920, 0.0062,&
1119 0.0200, 6.0106, 0.2474, 3.4788, 0.0622, 11.400, -40.50, 0.4820, 0.0077/),(/9,12/))
1123 k_para = k_soil(:,soil)
1124 sig_a = 1 - exp( -1 * k_para(1) * Z)
1125 sig_b = k_para(2) * Z**k_para(3)
1126 sig_c = k_para(4) * exp( -1 * Z**k_para(5))
1127 y = sig_a/(1 + exp(sig_b * (s - sig_c))) !solving equation (20) in Boogart et al.
1134 q_grav = -1 * ks * s**c
1136 ! alp is constant from equation (13) of paper
1138 alpha = 1 + 1.5 / (beta - 1)
1139 q_cap = ks * alpha * (aep / Z)**beta
1142 q_darcy = y * q_cap + q_grav ![cm/min]
1144 ! limit for exteme gradients with q >> saturated hydraulic conductivity
1145 ! if(q_cap > ks) q_cap = ks
1146 ! if(q_grav < -ks) q_grav = -ks
1148 ! if(q_darcy > ks) q_darcy = ks
1149 ! if(q_darcy < ks) q_darcy = -ks
1153 q_darcy = q_darcy * fac
1155 q_grav = q_grav * fac
1157 !returns q_darcy in [m/s]
1159 end subroutine darcyGwSoil
1163 subroutine aggregateQsgw(did)
1169 integer, intent(in) :: did
1170 integer :: j,i, ixxRT, jyyRT, m,n
1174 do j=1,rt_domain(did)%jx
1175 do i=1,rt_domain(did)%ix
1179 do m=nlst(did)%aggfactRT-1,0,-1
1180 do n=nlst(did)%aggfactRT-1,0,-1
1183 ixxRT = i * nlst(did)%aggfactRT-n
1184 jyyRT = j * nlst(did)%aggfactRT-m
1188 if(left_id.ge.0) ixxRT=ixxRT+1
1189 if(down_id.ge.0) jyyRT=jyyRT+1
1191 agg = agg + gw2d(did)%qdarcyRT(ixxRT, jyyRT)
1195 gw2d(did)%qsgw(i,j) = agg/(nlst(did)%aggfactRT**2)
1201 end subroutine aggregateQsgw
1203 ! Parallel tridiagonal solver useful for domain decomposed ADI
1204 ! Author(s): Mike Lambert
1206 ! Institution: Lawrence Livermore National Laboratory
1207 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
1208 ! for solution of the steady state diffusion equation",
1209 ! Parallel Computing 23 (1997) 2041-2065
1210 ! Ported to MPI by Benjamin Fersch, Karlsruhe Institute of Technology (2013)
1213 subroutine parysolv1(c,b,r,ct,pid,z_pid, &
1214 xsps, zsps, xdns, zdns)
1218 integer, intent(in) :: XSPS, &
1223 real, dimension(ZSPS, XSPS), intent(inout) :: c, &
1226 parameter (CLK_PER = 6.66666667e-9)
1228 real, dimension(0:ZSPS+1, 0:XSPS+1), intent(inout) :: r
1230 real, dimension(XSPS,2) :: zn, zntmp
1232 real, dimension(XSPS) :: t1, t2, fac
1234 real :: clockdt, click
1235 real :: ct, ti, tf, dt
1237 integer :: pid, z_pid
1238 integer :: i, j, sndr_pid, msg_type, cnt, ackn
1239 integer :: sendReq, recvReq
1242 parameter (ZN_REC = 46)
1244 integer :: source, dest
1251 if (z_pid .eq. 1) then
1253 ! Load (ZSPS,j)th equations into passing arrays.
1255 zntmp(j,1) = b(ZSPS,j)
1256 zntmp(j,2) = r(ZSPS,j)
1264 ! ! Send (ZSPS,j)th equations.
1265 ! ! Receive (ZSPS+1,j)th equations.
1267 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1268 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1269 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1270 call mpi_wait(sendReq, mpp_status, ierr)
1271 call mpi_wait(recvReq, mpp_status, ierr)
1275 call add_dt(ct,tf,ti,dt)
1279 ! Backward elimination in (ZSPS,j)th equations to get
1281 fac(j) = 1./(1. - b(ZSPS,j)*zn(j,1))
1282 r(ZSPS,j) = (r(ZSPS,j)-b(ZSPS,j)*zn(j,2))*fac(j)
1283 ! Forward elimination in (ZSPS+1,j)th equations to get
1285 r(ZSPS+1,j) = zn(j,2) - zn(j,1)*r(ZSPS,j)
1286 ! Completion of backward elimination to get remaining unknowns.
1288 r(i,j) = r(i,j) - b(i,j)*r(ZSPS,j)
1292 else if (z_pid .le. ZDNS/2) then
1297 ! ! Receive (0,j)th equations.
1299 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1300 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1301 call mpi_wait(recvReq, mpp_status, ierr)
1305 call add_dt(ct,tf,ti,dt)
1308 ! Forward elimination in (j,1)th equations.
1310 fac(j) = 1./(1. - c(1,j)*zn(j,1))
1311 ! Check for singular matrix (debugging only)
1312 b(1,j) = b(1,j)*fac(j)
1313 r(1,j) = (r(1,j) - c(1,j)*zn(j,2))*fac(j)
1314 ! Forward elimination in (ZSPS,j)th equations.
1315 fac(j) = 1./(1. - c(ZSPS,j)*b(1,j))
1316 ! Check for singular matrix (debugging only)
1317 b(ZSPS,j) = b(ZSPS,j)*fac(j)
1318 r(ZSPS,j) = (r(ZSPS,j)-c(ZSPS,j)*r(1,j))*fac(j)
1319 ! Store (0,j)th equations for later recovery of r(0,j).
1322 ! Load (ZSPS,j)th equations into passing arrays.
1323 zntmp(j,1) = b(ZSPS,j)
1324 zntmp(j,2) = r(ZSPS,j)
1330 ! ! Send (ZSPS,j)th equations.
1331 ! ! Receive (ZSPS+1,j)th equations.
1333 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1334 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1335 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1336 call mpi_wait(sendReq, mpp_status, ierr)
1337 call mpi_wait(recvReq, mpp_status, ierr)
1340 call add_dt(ct,tf,ti,dt)
1344 ! Backward elimination in (ZSPS,j)th equations.
1345 fac(j) = 1./(1. - b(ZSPS,j)*zn(j,1))
1346 ! Check for singular matrix (debugging only)
1347 r(ZSPS,j) = (r(ZSPS,j) - b(ZSPS,j)*zn(j,2))*fac(j)
1348 ! Backward elimination in (ZSPS+1,j)th equations.
1349 r(ZSPS+1,j) = zn(j,2) - zn(j,1)*r(ZSPS,j)
1350 ! Backward elimination in (ZSPS,j)th equations.
1351 r(1,j) = r(1,j) - b(1,j)*r(ZSPS,j)
1352 ! Load (1,j)th equations into passing arrays.
1360 ! ! Send (1,j)th equations.
1364 call add_dt(ct,tf,ti,dt)
1367 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1368 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1371 ! Backward elimination in (0,j)th equations.
1372 r(0,j) = t2(j) - t1(j)*r(1,j)
1374 ! Completion of forward and backward elimination to get remaining
1376 r(i,j) = r(i,j) - b(i,j)*r(ZSPS,j) - c(i,j)*r(1,j)
1380 call mpi_wait(sendReq, mpp_status, ierr)
1383 else if (z_pid .lt. ZDNS) then
1388 ! ! Receive (ZSPS+1,j)th equations.
1390 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1391 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1392 call mpi_wait(recvReq, mpp_status, ierr)
1396 call add_dt(ct,tf,ti,dt)
1400 ! Backward elimination in (ZSPS,j)th equations.
1401 fac(j) = 1./(1. - b(ZSPS,j)*zn(j,1))
1402 ! Check for singular matrix (debugging only)
1403 c(ZSPS,j) = c(ZSPS,j)*fac(j)
1404 r(ZSPS,j) = (r(ZSPS,j)-b(ZSPS,j)*zn(j,2))*fac(j)
1405 ! Backward elimination in (1,j)th equations.
1406 fac(j) = 1./(1. - b(1,j)*c(ZSPS,j))
1407 ! Check for singular matrix (debugging only)
1408 c(1,j) = c(1,j)*fac(j)
1409 r(1,j) = (r(1,j) - b(1,j)*r(ZSPS,j))*fac(j)
1410 ! Store (ZSPS+1,j)th equations for later recovery of
1414 ! Load passing arrays with (1,j)th equations.
1422 ! ! Send (1,j)th equations.
1423 ! ! Receive (0,j)th equations.
1425 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1426 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1427 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1428 call mpi_wait(sendReq, mpp_status, ierr)
1429 call mpi_wait(recvReq, mpp_status, ierr)
1433 call add_dt(ct,tf,ti,dt)
1437 ! Forward elimination in (1,j)th equations
1438 fac(j) = 1./(1. - c(1,j)*zn(j,1))
1439 ! Check for singular matrix (debugging only)
1440 r(1,j) = (r(1,j) - c(1,j)*zn(j,2))*fac(j)
1441 ! Backward elimination in (0,j)th equations.
1442 r(0,j) = zn(j,2) - zn(j,1)*r(1,j)
1443 ! Forward elimination in (ZSPS,j)th equations.
1444 r(ZSPS,j) = r(ZSPS,j) - c(ZSPS,j)*r(1,j)
1445 ! Load (ZSPS,j)th equations into passing arrays.
1447 zntmp(j,2) = r(ZSPS,j)
1453 ! ! Send (ZSPS,j)th equations.
1455 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1456 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1460 call add_dt(ct,tf,ti,dt)
1464 ! Forward elimination in (ZSPS+1,j)th equations to get
1466 r(ZSPS+1,j) = t2(j) - t1(j)*r(ZSPS,j)
1467 do 110 i = 2, ZSPS-1
1468 ! Completion of forward and backward elimination to get remaining unknowns.
1469 r(i,j) = r(i,j) - c(i,j)*r(1,j) - b(i,j)*r(ZSPS,j)
1473 call mpi_wait(sendReq, mpp_status, ierr)
1477 ! Load (1,j)th equations into passing arrays.
1486 ! ! Send (1,j)th equations.
1487 ! ! Receive (0,j)th equations.
1489 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1490 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1491 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1492 call mpi_wait(sendReq, mpp_status, ierr)
1493 call mpi_wait(recvReq, mpp_status, ierr)
1497 call add_dt(ct,tf,ti,dt)
1501 ! Forward elimination in (1,j)th equations to get r(1,j).
1502 fac(j) = 1./(1. - c(1,j)*zn(j,1))
1503 ! Check for singular matrix (debugging only)
1504 r(1,j) = (r(1,j) - c(1,j)*zn(j,2))*fac(j)
1505 ! Backward elimination in (0,j)th equations to get remaining unknowns.
1506 r(0,j) = zn(j,2) - zn(j,1)*r(1,j)
1508 ! Completion of forward elimination to get remaining unknowns.
1509 r(i,j) = r(i,j) - c(i,j)*r(1,j)
1519 ! Parallel tridiagonal solver useful for domain decomposed ADI
1520 ! Author(s): Mike Lambert
1522 ! Institution: Lawrence Livermore National Laboratory
1523 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
1524 ! for solution of the steady state diffusion equation",
1525 ! Parallel Computing 23 (1997) 2041-2065
1526 ! Ported to MPI by Benjamin Fersch, Karlsruhe Institute of Technology (2013)
1528 subroutine parxsolv1(c,b,r,ct,pid,x_pid, &
1529 xsps, zsps, xdns, zdns)
1533 integer, intent(in) :: XSPS, &
1538 real, dimension(ZSPS, XSPS), intent(inout) :: c, &
1542 real, dimension(0:ZSPS+1, 0:XSPS+1), intent(inout) :: r
1544 real, dimension(ZSPS,2) :: xn, xntmp
1547 parameter (XN_REC = 45)
1549 real, dimension(ZSPS) :: t1, t2, fac
1550 real :: clockdt, click
1551 real :: ct, ti, tf, dt
1553 integer :: pid, x_pid
1554 integer :: i, j, sndr_pid, msg_type, cnt, ackn
1555 integer :: sendReq, recvReq
1557 integer :: source, dest
1564 if (x_pid .eq. 1) then
1566 ! Load passing (i,XSPS)th equations into passing arrays.
1568 xntmp(i,1) = b(i,XSPS)
1569 xntmp(i,2) = r(i,XSPS)
1576 ! ! Send (i,XSPS)th equations.
1577 ! ! Receive (i,(XSPS + 1))th equations.
1579 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1580 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1581 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1582 call mpi_wait(sendReq, mpp_status, ierr)
1583 call mpi_wait(recvReq, mpp_status, ierr)
1587 call add_dt(ct,tf,ti,dt)
1591 ! Backward elimination in (i,XSPS)th equations to get
1593 fac(i) = 1./(1. - b(i,XSPS)*xn(i,1))
1594 r(i,XSPS) = (r(i,XSPS)-b(i,XSPS)*xn(i,2))*fac(i)
1595 ! Forward elimination in (i,XSPS+1)th equations to get
1597 r(i,XSPS+1) = xn(i,2) - xn(i,1)*r(i,XSPS)
1600 ! Completion of backward elimination to get remaining unknowns.
1603 r(i,j) = r(i,j) - b(i,j)*r(i,XSPS)
1606 else if (x_pid .le. XDNS/2) then
1612 ! ! Receive (i,0)th equations.
1614 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1615 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1616 call mpi_wait(recvReq, mpp_status, ierr)
1620 call add_dt(ct,tf,ti,dt)
1623 ! Forward elimination in (i,1)th equations of subdomain.
1625 fac(i) = 1./(1. - c(i,1)*xn(i,1))
1626 b(i,1) = b(i,1)*fac(i)
1627 r(i,1) = (r(i,1) - c(i,1)*xn(i,2))*fac(i)
1628 ! Forward elimination in (i,XSPS)th equations of subdomain.
1629 fac(i) = 1./(1. - c(i,XSPS)*b(i,1))
1630 b(i,XSPS) = b(i,XSPS)*fac(i)
1631 r(i,XSPS)=(r(i,XSPS)-c(i,XSPS)*r(i,1))*fac(i)
1632 ! Store (i,0)th equations for later recovery of r(i,0).
1635 ! Load (i,XSPS)th equations into passing arrays.
1636 xntmp(i,1) = b(i,XSPS)
1637 xntmp(i,2) = r(i,XSPS)
1644 ! ! Send (i,XSPS)th equations.
1645 ! ! Receive (i,(XSPS + 1))th equations.
1647 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1648 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1649 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1650 call mpi_wait(sendReq, mpp_status, ierr)
1651 call mpi_wait(recvReq, mpp_status, ierr)
1654 call add_dt(ct,tf,ti,dt)
1658 ! Backward elimination in (i,XSPS)th equations.
1659 fac(i) = 1./(1. - b(i,XSPS)*xn(i,1))
1660 r(i,XSPS) = (r(i,XSPS) - b(i,XSPS)*xn(i,2))*fac(i)
1661 ! Backward elimination in (i,XSPS+1)th equations.
1662 r(i,XSPS+1) = xn(i,2) - xn(i,1)*r(i,XSPS)
1663 ! Backward elimination in (i,1)th equations to get r(i,1).
1664 r(i,1) = r(i,1) - b(i,1)*r(i,XSPS)
1665 ! Load (i,1)th equations into passing array.
1674 ! ! Send (i,1)th equations.
1678 call add_dt(ct,tf,ti,dt)
1680 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1681 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1684 ! Backward elimination in (i,0)th equations.
1685 r(i,0) = t2(i) - t1(i)*r(i,1)
1688 ! Completion of forward and backward elimination for solution of
1692 r(i,j) = r(i,j) - b(i,j)*r(i,XSPS) - c(i,j)*r(i,1)
1695 call mpi_wait(sendReq, mpp_status, ierr)
1697 else if (x_pid .lt. XDNS) then
1703 ! ! Receive (i,XSPS+1)th equations.
1705 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1706 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1707 call mpi_wait(recvReq, mpp_status, ierr)
1711 call add_dt(ct,tf,ti,dt)
1715 ! Backward elimination in (i,XSPS)th equations.
1716 fac(i) = 1./(1. - b(i,XSPS)*xn(i,1))
1717 c(i,XSPS) = c(i,XSPS)*fac(i)
1718 r(i,XSPS) = (r(i,XSPS) - b(i,XSPS)*xn(i,2))*fac(i)
1719 ! Backward elimination in (i,1)th equations.
1720 fac(i) = 1./(1. - b(i,1)*c(i,XSPS))
1721 c(i,1) = c(i,1)*fac(i)
1722 r(i,1) = (r(i,1) - b(i,1)*r(i,XSPS))*fac(i)
1723 ! Store (i,XSPS+1)th equations for later recovery of r(i,XSPS+1).
1726 ! Load passing arrays with (i,1)th equations.
1735 ! ! Send (i,1)th equations.
1736 ! ! Receive (i,0)th equations.
1737 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1738 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1739 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1740 call mpi_wait(sendReq, mpp_status, ierr)
1741 call mpi_wait(recvReq, mpp_status, ierr)
1745 call add_dt(ct,tf,ti,dt)
1749 ! Forward elimination in (i,1)th equations
1750 fac(i) = 1./(1. - c(i,1)*xn(i,1))
1751 r(i,1) = (r(i,1) - c(i,1)*xn(i,2))*fac(i)
1752 ! Backward elimination in (i,0)th equations.
1753 r(i,0) = xn(i,2) - xn(i,1)*r(i,1)
1754 ! Forward elimination in (i,XSPS)th equations.
1755 r(i,XSPS) = r(i,XSPS) - c(i,XSPS)*r(i,1)
1756 ! Load (i,XSPS)th equations into passing arrays.
1758 xntmp(i,2) = r(i,XSPS)
1765 ! ! Send (i,XSPS)th equations.
1767 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1768 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1771 call add_dt(ct,tf,ti,dt)
1774 ! Forward elimination in (i,XSPS)th equations to get
1777 r(i,XSPS+1) = t2(i) - t1(i)*r(i,XSPS)
1780 ! Completion of forward and backward elimination to get remaining unknowns.
1781 do 110 j = 2, XSPS-1
1783 r(i,j) = r(i,j) - c(i,j)*r(i,1) - b(i,j)*r(i,XSPS)
1786 call mpi_wait(sendReq, mpp_status, ierr)
1790 ! Load (i,1)th equations into passing arrays.
1800 ! ! Send (i,1)th equations.
1801 ! ! Receive (i,0)th equations.
1803 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1804 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1805 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1806 call mpi_wait(sendReq, mpp_status, ierr)
1807 call mpi_wait(recvReq, mpp_status, ierr)
1811 call add_dt(ct,tf,ti,dt)
1815 ! Forward elimination in (i,1)th equations to get r(i,1).
1816 fac(i) = 1./(1. - c(i,1)*xn(i,1))
1817 r(i,1) = (r(i,1) - c(i,1)*xn(i,2))*fac(i)
1818 ! Backward elimination in (i,0)th equations to get r(i,0).
1819 r(i,0) = xn(i,2) - xn(i,1)*r(i,1)
1822 ! Completion of forward elimination to get remaining unknowns.
1825 r(i,j) = r(i,j) - c(i,j)*r(i,1)
1834 ! Parallel tridiagonal solver useful for domain decomposed ADI
1835 ! Author(s): Mike Lambert
1837 ! Institution: Lawrence Livermore National Laboratory
1838 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
1839 ! for solution of the steady state diffusion equation",
1840 ! Parallel Computing 23 (1997) 2041-2065
1842 subroutine sub_n_form(n_xs,n_zs,c,a,b,r,c2,b2,r2,wk,xfac,zfac, &
1849 ! c(,) -- subdiagonal elements of tridiagonal systems
1850 ! a(,) -- diagonal elements of tridiagonal systems
1851 ! b(,) -- superdiagonal elements of tridiagonal systems
1852 ! r(,) -- right-hand side elements of tridiagonal systems
1853 ! c2(,) -- front-leg elements of N-systems
1854 ! b2(,) -- back-leg elements of N-systems
1855 ! r2(,) -- right-hand side elements of N-systems
1856 ! wk(,) -- work array with same dimensions as a, b, c, etc.
1863 real r2(0:n_zs+1,0:n_xs+1)
1869 integer dpid,dn_subs,dir
1870 integer i, j, XDIR, ZDIR
1871 parameter (XDIR = 1, ZDIR = 2)
1873 if (dir .eq. XDIR) then
1875 ! Forward elimination of subdiagonal elements
1876 if (dpid .eq. 1) then
1881 r2(i,1) = r(i,1)*xfac(i)
1886 wk(i,j-1) = b(i,j-1)*xfac(i)
1887 xfac(i) = 1./(a(i,j) - c(i,j)*wk(i,j-1))
1889 r2(i,j) = (r(i,j) - c(i,j)*r2(i,j-1))*xfac(i)
1893 b2(i,n_xs) = b(i,n_xs)*xfac(i)
1900 c2(i,1) = c(i,1)*xfac(i)
1901 wk(i,1) = b(i,1)*xfac(i)
1902 r2(i,1) = r(i,1)*xfac(i)
1904 c2(i,2) = c(i,2)*xfac(i)
1905 r2(i,2) = r(i,2)*xfac(i)
1910 wk(i,j-1) = b(i,j-1)*xfac(i)
1911 xfac(i) = 1./(a(i,j) - c(i,j)*wk(i,j-1))
1912 c2(i,j) = -c(i,j)*c2(i,j-1)*xfac(i)
1913 r2(i,j) = (r(i,j) - c(i,j)*r2(i,j-1))*xfac(i)
1917 b2(i,n_xs) = b(i,n_xs)*xfac(i)
1922 ! Backward elimination of superdiagonal elements
1923 if (dpid .eq. dn_subs) then
1925 do 90 j = n_xs-1, 2, -1
1927 c2(i,j) = c2(i,j) - wk(i,j)*c2(i,j+1)
1929 r2(i,j) = r2(i,j) - wk(i,j)*r2(i,j+1)
1933 fac = 1./(1. - wk(i,1)*c2(i,2))
1934 c2(i,1) = c2(i,1)*fac
1936 r2(i,1) = (r2(i,1) - wk(i,1)*r2(i,2))*fac
1942 b2(i,n_xs-1) = wk(i,n_xs-1)
1945 do 120 j = n_xs-2, 2, -1
1947 c2(i,j) = c2(i,j) - wk(i,j)*c2(i,j+1)
1948 b2(i,j) = -wk(i,j)*b2(i,j+1)
1949 r2(i,j) = r2(i,j) - wk(i,j)*r2(i,j+1)
1952 ! If only 2 points in X-direction, do not execute these statements.
1953 if (n_xs .gt. 2) then
1955 fac = 1./(1. - wk(i,1)*c2(i,2))
1956 c2(i,1) = c2(i,1)*fac
1957 r2(i,1) = (r2(i,1) - wk(i,1)*r2(i,2))*fac
1958 b2(i,1) = -wk(i,1)*b2(i,2)*fac
1964 else if (dir .eq. ZDIR) then
1966 ! Forward elimination of subdiagonal elements
1967 if (dpid .eq. 1) then
1972 r2(1,j) = r(1,j)*zfac(j)
1977 wk(i-1,j) = b(i-1,j)*zfac(j)
1978 zfac(j) = 1./(a(i,j) - c(i,j)*wk(i-1,j))
1980 r2(i,j) = (r(i,j) - c(i,j)*r2(i-1,j))*zfac(j)
1984 b2(n_zs,j) = b(n_zs,j)*zfac(j)
1991 c2(1,j) = c(1,j)*zfac(j)
1992 wk(1,j) = b(1,j)*zfac(j)
1993 r2(1,j) = r(1,j)*zfac(j)
1995 c2(2,j) = c(2,j)*zfac(j)
1996 r2(2,j) = r(2,j)*zfac(j)
2001 wk(i-1,j) = b(i-1,j)*zfac(j)
2002 zfac(j) = 1./(a(i,j) - c(i,j)*wk(i-1,j))
2003 c2(i,j) = -c(i,j)*c2(i-1,j)*zfac(j)
2004 r2(i,j) = (r(i,j) - c(i,j)*r2(i-1,j))*zfac(j)
2008 b2(n_zs,j) = b(n_zs,j)*zfac(j)
2013 ! Backward elimination of superdiagonal elements
2014 if (dpid .eq. dn_subs) then
2017 do 220 i = n_zs - 1, 2, -1
2018 c2(i,j) = c2(i,j) - wk(i,j)*c2(i+1,j)
2020 r2(i,j) = r2(i,j) - wk(i,j)*r2(i+1,j)
2024 fac = 1./(1. - wk(1,j)*c2(2,j))
2025 c2(1,j) = c2(1,j)*fac
2027 r2(1,j) = (r2(1,j) - wk(1,j)*r2(2,j))*fac
2033 b2(n_zs-1,j) = wk(n_zs-1,j)
2037 do 250 i = n_zs - 2, 2, -1
2038 c2(i,j) = c2(i,j) - wk(i,j)*c2(i+1,j)
2039 b2(i,j) = -wk(i,j)*b2(i+1,j)
2040 r2(i,j) = r2(i,j) - wk(i,j)*r2(i+1,j)
2043 ! If only 2 points in Z-direction, do not execute these statements.
2044 if (n_zs .gt. 2) then
2046 fac = 1./(1. - wk(1,j)*c2(2,j))
2047 c2(1,j) = c2(1,j)*fac
2048 r2(1,j) = (r2(1,j) - wk(1,j)*r2(2,j))*fac
2049 b2(1,j) = -wk(1,j)*b2(2,j)*fac
2055 ! Announce bad direction specifier (debugging only)
2057 ! write(*,*) 'sub_n_form: What direction?'
2065 ! Tridiagonal solver useful for domain decomposed ADI
2066 ! Author(s): Mike Lambert
2068 ! Institution: Lawrence Livermore National Laboratory
2069 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
2070 ! for solution of the steady state diffusion equation",
2071 ! Parallel Computing 23 (1997) 2041-2065
2073 subroutine sub_tri_solv(n_xs,n_zs,c,a,b,r,x,wk,xfac,zfac,dir)
2079 ! c(,) -- subdiagonal elements of tridiagonal systems
2080 ! a(,) -- diagonal elements of tridiagonal systems
2081 ! b(,) -- superdiagonal elements of tridiagonal systems
2082 ! r(,) -- right-hand side elements of tridiagonal systems
2084 ! wk(,) -- work array w/ same dimensions as c, a, b, etc.
2090 real x(0:n_zs+1,0:n_xs+1)
2096 integer i,j,XDIR,ZDIR
2098 parameter (XDIR = 1, ZDIR = 2)
2100 if (dir .eq. XDIR) then
2103 ! Check for need to pivot (debugging only)
2105 x(i,1) = r(i,1)*xfac(i)
2108 ! Forward subdiagonal elimination
2111 wk(i,j-1) = b(i,j-1)*xfac(i)
2112 xfac(i) = 1./(a(i,j) - c(i,j)*wk(i,j-1))
2113 ! Check for need to pivot (debugging only)
2114 x(i,j) = (r(i,j) - c(i,j)*x(i,j-1))*xfac(i)
2118 do 30 j = n_xs - 1, 1, -1
2120 x(i,j) = x(i,j) - wk(i,j)*x(i,j+1)
2124 else if (dir .eq. ZDIR) then
2127 ! Check for need to pivot (debugging only)
2129 x(1,j) = r(1,j)*zfac(j)
2132 ! Forward subdiagonal elimination
2135 wk(i-1,j) = b(i-1,j)*zfac(j)
2136 zfac(j) = 1./(a(i,j) - c(i,j)*wk(i-1,j))
2137 ! Check for need to pivot (debugging only)
2138 x(i,j) = (r(i,j) - c(i,j)*x(i-1,j))*zfac(j)
2144 do i = n_zs - 1, 1, -1
2145 x(i,j) = x(i,j) - wk(i,j)*x(i+1,j)
2149 ! Announce bad direction specifier (debugging only)
2151 ! write(*,*) 'sub_tri_solv: What direction?'
2159 end module module_gw_gw2d