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, gw_field
33 use module_rt_data, only: rt_domain
34 use config_base, only: nlst
40 integer, private :: ierr
41 integer, parameter :: rowshift = 0
42 integer, parameter :: colshift = 1
49 subroutine gw2d_ini(did,dt,dx)
51 use module_HYDRO_io, only: output_gw_spinup
56 integer :: jj, ii, iter, itermax
61 itermax = nlst(did)%GwPreCycles
65 gw2d(did)%qgw_chanrt = 0.
67 gw2d(did)%qdarcyRT = 0.
70 gw2d(did)%compres=0. ! currently not implemented
71 gw2d(did)%istep=0 ! initialize time step
72 ! reset cells with undefined hydraulic conductivity
73 where(gw2d(did)%hycond .eq. 100) gw2d(did)%hycond = 5E-4
78 if(my_id .eq. IO_id) &
80 write(6,*) " GW Pre-cycle", iter, "of", itermax
82 call gwstep(gw2d(did)%ix, gw2d(did)%jx, gw2d(did)%dx, &
83 gw2d(did)%ltype, gw2d(did)%elev, gw2d(did)%bot, &
84 gw2d(did)%hycond, gw2d(did)%poros, gw2d(did)%compres, &
85 gw2d(did)%ho, gw2d(did)%h, gw2d(did)%convgw, gw2d(did)%excess, &
86 gw2d(did)%ebot, gw2d(did)%eocn, gw2d(did)%dt, &
89 gw2d(did)%ho = gw2d(did)%h
91 if((nlst(did)%GwPreDiag .and. iter==1) .or. &
92 nlst(did)%GwPreDiag .and. (mod(iter, nlst(did)%GwPreDiagInterval) .eq. 0) ) then
93 call output_gw_spinup(nlst(did)%igrid, 1000000, &
94 RT_DOMAIN(did)%ixrt, RT_DOMAIN(did)%jxrt, &
95 nlst(did)%startdate, nlst(did)%olddate, &
96 gw2d(did)%ho, gw2d(did)%convgw, gw2d(did)%excess, &
97 nlst(did)%geo_finegrid_flnm,nlst(did)%DT, &
98 RT_DOMAIN(did)%LATVAL, &
99 RT_DOMAIN(did)%LONVAL,rt_domain(did)%overland%properties%distance_to_neighbor, &
107 end subroutine gw2d_ini
109 subroutine gw2d_allocate(did, ix, jx, nsoil)
112 integer ix, jx, nsoil
115 if(gw2d(did)%allo_status .eq. 1) return
116 gw2d(did)%allo_status = 1
122 if(down_id == -1) then ! if south border
128 if(up_id == -1) then !if north border
134 if(left_id == -1) then !if west border
140 if(right_id == -1) then ! if east border
153 allocate(gw2d(did)%ltype (ix,jx))
154 allocate(gw2d(did)%elev (ix,jx))
155 allocate(gw2d(did)%bot (ix,jx))
156 allocate(gw2d(did)%hycond (ix,jx))
157 allocate(gw2d(did)%poros (ix,jx))
158 allocate(gw2d(did)%compres(ix,jx))
159 allocate(gw2d(did)%ho (ix,jx))
160 allocate(gw2d(did)%h (ix,jx))
161 allocate(gw2d(did)%convgw (ix,jx))
162 allocate(gw2d(did)%excess (ix,jx))
164 allocate(gw2d(did)%qgw_chanrt (ix,jx))
167 ! TODO allocate only if gwSoilCoupling is active
168 allocate(gw2d(did)%qsgwrt (ix,jx))
169 allocate(gw2d(did)%qsgw (rt_domain(did)%ix,rt_domain(did)%jx))
170 allocate(gw2d(did)%qdarcyRT (ix,jx))
172 end subroutine gw2d_allocate
175 subroutine gwstep(ix, jx, dx, &
177 hycond, poros, compres, &
178 ho, h, convgw, excess, &
182 ! New (volug): calling routines use change in head, convgw = d(h-ho)/dt.
184 ! Steps ground-water hydrology (head) through one timestep.
185 ! Modified from Prickett and Lonnquist (1971), basic one-layer aquifer
186 ! simulation program, with mods by Zhongbo Yu(1997).
187 ! Solves S.dh/dt = d/dx(T.dh/dx) + d/dy(T.dh/dy) + "external sources"
188 ! for a single layer, where h is head, S is storage coeff and T is
189 ! transmissivity. 3-D arrays in main program (hycond,poros,h,bot)
190 ! are 2-D here, since only a single (uppermost) layer is solved.
191 ! Uses an iterative time-implicit ADI method.
193 ! use module_hms_constants
197 integer, intent(in) :: ix, jx
199 integer, intent(in), dimension(ix,jx) :: ltype ! land-sfc type (supp)
200 real, intent(in), dimension(ix,jx) :: &
201 elev, & ! elev/bathymetry of sfc rel to sl (m) (supp)
202 bot, & ! elev. aquifer bottom rel to sl (m) (supp)
203 hycond, & ! hydraulic conductivity (m/s per m/m) (supp)
204 poros, & ! porosity (m3/m3) (supp)
205 compres, & ! compressibility (1/Pa) (supp)
206 ho ! head at start of timestep (m) (supp)
208 real, intent(inout), dimension(ix,jx) :: &
209 h, & ! head, after ghmcompute (m) (ret)
210 convgw, & ! convergence due to gw flow (m/s) (ret)
213 real, intent(inout) :: ebot, eocn
217 integer :: istep !, dt
218 real, intent(in) :: dt, dx
221 ! eocn = mean spurious sink for h_ocn = sealev fix (m/s)(ret)
222 ! This equals the total ground-water flow across
223 ! land->ocean boundaries.
224 ! ebot = mean spurious source for "bot" fix (m/s) (returned)
225 ! time = elapsed time from start of run (sec)
226 ! dt = timestep length (sec)
227 ! istep = timestep counter
231 real, dimension(ix,jx) :: sf2 ! storage coefficient (m3 of h2o / bulk m3)
232 real, dimension(ix,jx,2) :: t ! transmissivity (m2/s)..1 for N-S,..2 for E-W
235 real, dimension(:,:), allocatable :: aa, & ! tridiagonal matrix lower diagonal
236 bb, & ! tridiagonal matrix main diagonal
237 cc, & ! tridiagonal matrix upper diagonal
238 dd, & ! right hand side
244 real, dimension(:), allocatable :: xfac, &
247 real, dimension(:), allocatable :: aa, & ! tridiagonal matrix lower diagonal
248 bb, & ! tridiagonal matrix main diagonal
249 cc, & ! tridiagonal matrix upper diagonal
250 dd, & ! right hand side
253 real, parameter :: botinc = 0.01 ! re-wetting increment to fix h < bot
254 ! parameter (botinc = 0. ) ! re-wetting increment to fix h < bot
255 ! (m); else no flow into dry cells
256 real, parameter :: delskip = 0.005 ! av.|dhead| value for iter.skip out(m)
257 integer, parameter :: itermax = 1 ! maximum number of iterations
258 integer, parameter :: itermin = 1 ! minimum number of iterations
259 real, parameter :: sealev = 1000. ! sea-level elevation (m)
261 integer :: its, ite, jts, jte, ifs, ife, jfs, jfe, &
262 xdim, ydim, fxdim, fydim
264 ! die müssen noch sortiert, geprüft und aufgeräumt werden
277 ! real :: su, sc, shp, bb, aa, cc, w, zz, tareal, dtoa, dtot
307 ! define indexes for parallel execution
310 if(down_id == -1) then ! if south border
316 if(up_id == -1) then !if north border
322 if(left_id == -1) then !if west border
328 if(right_id == -1) then ! if east border
353 call scopy (fxdim*fydim, ho(ifs:ife,jfs:jfe), 1, &
354 h(ifs:ife,jfs:jfe), 1)
357 ! Top of iterative loop for (not anymore ADI) solution
368 call MPP_LAND_COM_REAL(h, fxdim, fydim, 99)
371 e = 0. ! absolute changes in head (for iteration control)
372 ! eocn = 0. ! accumulated fixes for h = 0 over ocean (diag)
373 ! ebot = 0. ! accumulated fixes for h < bot (diagnostic)
375 ! Set storage coefficient (sf2)
384 if(ltype(i,j) .ge. 1) tareal = tareal + darea
386 ! unconfined water table (h < e): V = poros*(h-b)
388 ! saturated to surface (h >= e) : V = poros*(e-b) + (h-e)
390 ! (compressibility is ignored)
392 ! su = poros(i,j)*(1.-theta(i,j)) ! old (pre-volug)
393 su = poros(i,j) ! new (volug)
396 ! if (ho(i,j).le.elev(i,j) .and. h(i,j).le.elev(i,j)) then
398 ! else if (ho(i,j).ge.elev(i,j) .and. h(i,j).ge.elev(i,j)) then
400 ! else if (ho(i,j).le.elev(i,j) .and. h(i,j).ge.elev(i,j)) then
401 ! shp = sf2(i,j) * (h(i,j) - ho(i,j))
402 ! sf2(i,j) = shp * sc / (shp - (su-sc)*(elev(i,j)-ho(i,j)))
403 ! else if (ho(i,j).ge.elev(i,j) .and. h(i,j).le.elev(i,j)) then
404 ! shp = sf2(i,j) * (ho(i,j) - h(i,j))
405 ! sf2(i,j) = shp * su / (shp + (su-sc)*(ho(i,j)-elev(i,j)))
412 ! communicate storage coefficient
413 call MPP_LAND_COM_REAL(sf2, fxdim, fydim, 99)
417 !==========================
418 ! Column calculations
419 !==========================
421 ! Set transmissivities. Use min(h,elev)-bot instead of h-bot,
422 ! since if h > elev, thickness of groundwater flow is just
423 ! elev-bot. (uses geometric mean)
431 t(i,j,2) = sqrt( abs( &
432 hycond(i, j)*(min(h(i ,j),elev(i ,j))-bot(i ,j)) &
433 *hycond(ip,j)*(min(h(ip,j),elev(ip,j))-bot(ip,j)) &
435 * (0.5*(dy+dy)) & ! in WRF the dx and dy are usually equal
438 t(i,j,1) = sqrt( abs( &
439 hycond(i,j )*(min(h(i,j ),elev(i,j ))-bot(i,j )) &
440 *hycond(i,jp)*(min(h(i,jp),elev(i,jp))-bot(i,jp)) &
454 ! communicate transmissivities in x and y direction
455 call MPP_LAND_COM_REAL(t(:,:,1), fxdim, fydim, 99)
456 call MPP_LAND_COM_REAL(t(:,:,2), fxdim, fydim, 99)
459 allocate(aa(jts:jte,its:ite))
460 allocate(bb(jts:jte,its:ite))
461 allocate(cc(jts:jte,its:ite))
462 allocate(dd(jts:jte,its:ite))
463 allocate(c2(1:ydim,1:xdim))
464 allocate(b2(1:ydim,1:xdim))
465 allocate(wk(1:ydim,1:xdim))
466 allocate(hh(0:ydim+1,0:xdim+1))
467 allocate(xfac(1:ydim))
468 allocate(zfac(1:ydim))
470 allocate(aa(jfs:jfe))
471 allocate(bb(jfs:jfe))
472 allocate(cc(jfs:jfe))
473 allocate(dd(jfs:jfe))
474 allocate(hh(jfs:jfe))
480 !>>>>>>>>>>>>>>>>>>>>
482 !>>>>>>>>>>>>>>>>>>>>
485 bb(j) = (sf2(i,j)/dt) * darea
486 dd(j) = ( ho(i,j)*sf2(i,j)/dt ) * darea
490 if ((j-jfs) /= 0) then
492 bb(j) = bb(j) + t(i,j-1,1)
495 if ((j-jfe) /= 0) then
497 bb(j) = bb(j) + t(i,j,1)
500 if ((i-ifs) /= 0) then
501 bb(j) = bb(j) + t(i-1,j,2)
502 dd(j) = dd(j) + h(i-1,j)*t(i-1,j,2)
505 if ((i-ife) /= 0) then
506 bb(j) = bb(j) + t(i,j,2)
507 dd(j) = dd(j) + h(i+1,j)*t(i,j,2)
514 call trdiagSolve(aa, bb, cc, dd, hh, fydim)
530 !>>>>>>>>>>>>>>>>>>>>
532 !>>>>>>>>>>>>>>>>>>>>
533 bb(j,i) = (sf2(i,j)/dt) * darea
534 dd(j,i) = ( ho(i,j)*sf2(i,j)/dt ) * darea
538 if (((j-jfs) /= 0)) then
539 aa(j,i) = -t(i,j-1,1)
540 bb(j,i) = bb(j,i) + t(i,j-1,1)
543 if (((j-jfe) /= 0)) then
545 bb(j,i) = bb(j,i) + t(i,j,1)
548 if (((i-ifs) /= 0)) then
549 bb(j,i) = bb(j,i) + t(i-1,j,2)
550 dd(j,i) = dd(j,i) + h(i-1,j)*t(i-1,j,2)
553 if (((i-ife) /= 0)) then
554 bb(j,i) = bb(j,i) + t(i,j,2)
555 dd(j,i) = dd(j,i) + h(i+1,j)*t(i,j,2)
566 if(np_up_down .gt. 1) then
567 call sub_n_form(xdim, ydim, aa, &
570 c2, b2, hh, wk, xfac, zfac, &
571 p_up_down+1, np_up_down, 2)
574 call parysolv1(c2, b2, hh, 1., my_id+1, p_up_down+1, &
575 xdim, ydim, np_left_right, np_up_down)
578 call sub_tri_solv(xdim,ydim,aa(jts:jte,its:ite), &
579 bb(jts:jte,its:ite), cc(jts:jte,its:ite), &
580 dd(jts:jte,its:ite), &
590 !>>>>>>>>>>>>>>>>>>>>
592 !>>>>>>>>>>>>>>>>>>>>
594 h(i,j) = hh(j-joffs,i-ioffs)
603 call MPP_LAND_COM_REAL(h, fxdim, fydim, 99)
608 !=======================
610 !=======================
612 ! set transmissivities (same as above)
619 t(i,j,2) = sqrt( abs( &
620 hycond(i, j)*(min(h(i ,j),elev(i ,j))-bot(i ,j)) &
621 *hycond(ip,j)*(min(h(ip,j),elev(ip,j))-bot(ip,j)) &
626 t(i,j,1) = sqrt( abs( &
627 hycond(i,j )*(min(h(i,j ),elev(i,j ))-bot(i,j )) &
628 *hycond(i,jp)*(min(h(i,jp),elev(i,jp))-bot(i,jp)) &
638 ! communicate transmissivities in x and y direction
639 call MPP_LAND_COM_REAL(t(:,:,1), fxdim, fydim, 99)
640 call MPP_LAND_COM_REAL(t(:,:,2), fxdim, fydim, 99)
644 allocate(aa(ifs:ife))
645 allocate(bb(ifs:ife))
646 allocate(cc(ifs:ife))
647 allocate(dd(ifs:ife))
648 allocate(hh(ifs:ife))
656 !>>>>>>>>>>>>>>>>>>>>
658 !>>>>>>>>>>>>>>>>>>>>
659 bb(i) = (sf2(i,j)/dt) * darea
660 dd(i) = ( ho(i,j)*sf2(i,j)/dt ) * darea
664 if ((j-jfs) /= 0) then
665 bb(i) = bb(i) + t(i,j-1,1)
666 dd(i) = dd(i) + h(i,j-1)*t(i,j-1,1)
669 if ((j-jfe) /= 0) then
670 dd(i) = dd(i) + h(i,j+1)*t(i,j,1)
671 bb(i) = bb(i) + t(i,j,1)
674 if ((i-ifs) /= 0) then
675 bb(i) = bb(i) + t(i-1,j,2)
679 if ((i-ife) /= 0) then
680 bb(i) = bb(i) + t(i,j,2)
688 call trdiagSolve(aa, bb, cc, dd, hh, fxdim)
698 !>>>>>>>>>>>>>>>>>>>>
700 !>>>>>>>>>>>>>>>>>>>>
701 bb(j,i) = (sf2(i,j)/dt) * darea
702 dd(j,i) = ( ho(i,j)*sf2(i,j)/dt ) * darea
706 if (((j-jfs) /= 0)) then
707 bb(j,i) = bb(j,i) + t(i,j-1,1)
708 dd(j,i) = dd(j,i) + h(i,j-1)*t(i,j-1,1)
711 if (((j-jfe) /= 0)) then
712 dd(j,i) = dd(j,i) + h(i,j+1)*t(i,j,1)
713 bb(j,i) = bb(j,i) + t(i,j,1)
716 if (((i-ifs) /= 0)) then
717 bb(j,i) = bb(j,i) + t(i-1,j,2)
718 aa(j,i) = -t(i-1,j,2)
721 if (((i-ife) /= 0)) then
722 bb(j,i) = bb(j,i) + t(i,j,2)
734 if(np_left_right .gt. 1) then
736 ! 3 c(,) -- subdiagonal elements of tridiagonal systems
737 ! 4 a(,) -- diagonal elements of tridiagonal systems
738 ! 5 b(,) -- superdiagonal elements of tridiagonal systems
739 ! 6 r(,) -- right-hand side elements of tridiagonal systems
740 ! 7 c2(,) -- front-leg elements of N-systems
741 ! 8 b2(,) -- back-leg elements of N-systems
742 ! 9 r2(,) -- right-hand side elements of N-systems (0:ydim+1,0:xdim+1)
743 ! 10 wk(,) -- work array with same dimensions as a, b, c, etc.
745 call sub_n_form(xdim, ydim, aa, &
748 c2, b2, hh, wk, xfac, zfac, &
749 p_left_right+1, np_left_right, 1)
751 call parxsolv1(c2, b2, hh, 1., my_id+1, p_left_right+1, &
752 xdim, ydim, np_left_right, np_up_down)
755 call sub_tri_solv(xdim,ydim,aa, &
766 !>>>>>>>>>>>>>>>>>>>>
768 !>>>>>>>>>>>>>>>>>>>>
770 h(i,j) = hh(j-joffs,i-ioffs)
787 ! fix head < bottom of aquifer
791 if (ltype(i,j).eq.1 .and. h(i,j).le.bot(i,j)+botinc) then
793 e = e + bot(i,j) + botinc - h(i,j)
794 ! ebot = ebot + (bot(i,j)+botinc-h(i,j))*sf2(i,j)*darea(i,j)
795 ebot = ebot + (bot(i,j)+botinc-h(i,j))*sf2(i,j)*darea
797 h(i,j) = bot(i,j) + botinc
801 ! maintain head = sea level for ocean (only for adjacent ocean,
806 if (ltype(i,j).eq.2) then
808 eocn = eocn + (h(i,j)-sealev)*sf2(i,j)*darea
809 ! eocn = eocn + (h(i,j)-sealev)*sf2(i,j)*darea(i,j)
811 ! h(i,j) = sealev (no update of outer boundary cells)
816 ! Loop back for next ADI iteration
818 !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
819 delcur = e/(xdim*ydim)
821 ! print*, 'delcur before mpi:', delcur
825 call mpi_reduce(delcur, mpiDelcur, 1, MPI_REAL, MPI_SUM, 0, HYDRO_COMM_WORLD, ierr)
826 call MPI_COMM_SIZE( HYDRO_COMM_WORLD, mpiSize, ierr )
828 if(my_id .eq. IO_id) delcur = mpiDelcur/mpiSize
830 call mpi_bcast(delcur, 1, mpi_real, 0, HYDRO_COMM_WORLD, ierr)
834 ! if ( (delcur.gt.delskip*dt/86400. .and. iter.lt.itermax) &
835 if ( (delcur.gt.delskip .and. iter.lt.itermax) &
836 .or. iter.lt.itermin ) then
841 if(my_id .eq. IO_id) write(6,*) "Iteration", iter, "of", itermax, "error:", delcur
843 write(6,*) "Iteration", iter, "of", itermax, "error:", delcur
853 call MPP_LAND_COM_REAL(h, fxdim, fydim, 99)
859 ! Compute exfiltration amount and
860 ! convergence rate due to ground water
866 if((elev(i,j) - h(i,j)) .lt. 0.) then
867 excess(i,j) = sf2(i,j)*(h(i,j) - elev(i,j))
873 if(ltype(i,j).eq.1) then
874 convgw(i,j) = sf2(i,j) * (h(i,j)-ho(i,j)) / dt
881 ! call MPP_LAND_COM_REAL(convgw, fxdim, fydim, 99)
883 ! Diagnostic water conservation check for this timestep
885 dtot = 0. ! total change in water storage (m3)
890 if (ltype(i,j).eq.1) then
892 dtot = dtot + sf2(i,j) *(h(i,j)-ho(i,j)) * darea
893 dtoa = dtoa + sf2(i,j) * abs(h(i,j)-ho(i,j)) * darea
895 ! dtot = dtot + sf2(i,j) *(h(i,j)-ho(i,j)) * darea(i,j)
896 ! dtoa = dtoa + sf2(i,j) * abs(h(i,j)-ho(i,j)) * darea(i,j)
901 dtot = (dtot/tareal)/dt ! convert to m/s, rel to land area
902 dtoa = (dtoa/tareal)/dt
903 eocn = (eocn/tareal)/dt
904 ebot = (ebot/tareal)/dt
906 zz = 1.e3 * 86400. ! convert printout to mm/day
910 call MPI_REDUCE(dtot,gdtot,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
911 call MPI_REDUCE(dtoa,gdtoa,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
912 call MPI_REDUCE(eocn,geocn,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
913 call MPI_REDUCE(ebot,gebot,1, MPI_REAL, MPI_SUM, IO_id, HYDRO_COMM_WORLD, ierr)
915 if(my_id .eq. IO_id) then
917 gdtot*zz, gdtoa*zz, -geocn*zz, gebot*zz, &
918 (gdtot-(-geocn+gebot))*zz
924 dtot*zz, dtoa*zz, -eocn*zz, ebot*zz, &
925 (dtot-(-eocn+ebot))*zz
929 (3x,' dh/dt |dh/dt| ocnflx botfix',&
931 ! /3x,4f9.4,2(9x),e14.4)
935 end subroutine gwstep
938 SUBROUTINE SCOPY (NT, ARR, INCA, BRR, INCB)
940 ! Copies array ARR to BRR, incrementing by INCA and INCB
941 ! respectively, up to a total length of NT words of ARR.
942 ! (Same as Cray SCOPY.)
944 real, DIMENSION(*) :: ARR, BRR
945 integer :: ia, nt, inca, incb, ib
957 subroutine trdiagSolve(a,b,c,rhs,x,n)
961 integer,intent(in) :: n
962 real,dimension(n),intent(in) :: a, b, c, rhs
963 real,dimension(n),intent(out) :: x
964 real,dimension(n) :: cp, dp
968 ! initialize c-prime and d-prime
971 ! solve for vectors c-prime and d-prime
973 m = b(i)-cp(i-1)*a(i)
975 dp(i) = (rhs(i)-dp(i-1)*a(i))/m
979 ! solve for x from the vectors c-prime and d-prime
981 x(i) = dp(i)-cp(i)*x(i+1)
985 end subroutine trdiagSolve
988 subroutine gwSoilFlux(did)
993 integer, intent(in) :: did
996 real, dimension(rt_domain(did)%ixrt,rt_domain(did)%jxrt) :: smcrel, ztrans, headChange
998 integer :: nsoil, i, j, k
1000 gw2d(did)%qsgwrt = 0.
1001 gw2d(did)%qdarcyRT = 0.
1003 ! Step 1, collect data
1005 ! relative soil moisture content of lowest soil layer (1 = saturated)
1006 nsoil = nlst(did)%nsoil
1007 smcrel = rt_domain(did)%subsurface%grid_transform%smcrt(:,:,nsoil) / RT_DOMAIN(did)%subsurface%grid_transform%smcmaxrt(:,:,nsoil)
1009 ! depth of transition zone from lowest soil layer to groundwater head (in cm)
1010 ! postivie ztrans -> head below LSM soil layer
1011 ! negative ztrans -> head within LSM soil layers
1012 ztrans = (rt_domain(did)%elrt + nlst(did)%zsoil8(nsoil)) - gw2d(did)%ho
1013 ztrans = ztrans * 100
1015 ! darcyGwSoil not defined for ztran = 0
1016 where(ztrans == 0) ztrans = -5
1018 ! Step 2, compute flux either up or down
1020 do j=gw2d(did)%jts, gw2d(did)%jte
1021 do i=gw2d(did)%its, gw2d(did)%ite
1023 if((ztrans(i,j) > 0) .and. (rt_domain(did)%soiltypRT(i,j) < 13)) then
1024 ! if groundwater head < soil layers
1025 call darcyGwSoil(ztrans(i,j), smcrel(i,j), rt_domain(did)%soiltypRT(i,j), gw2d(did)%qdarcyRT(i,j))
1027 gw2d(did)%qsgwrt(i,j) = gw2d(did)%qdarcyRT(i,j)
1029 ! check and correct for mass balance
1030 if(((gw2d(did)%ho(i,j)-gw2d(did)%bot(i,j)) &
1031 *gw2d(did)%poros(i,j)) < (gw2d(did)%qsgwrt(i,j)*gw2d(did)%dt)) then
1033 gw2d(did)%qdarcyRT(i,j) = 0.
1034 gw2d(did)%qsgwrt(i,j) = 0.
1038 else if(ztrans(i,j) < 0 .and. (rt_domain(did)%soiltypRT(i,j) < 13)) then
1039 ! if groundwater head > soil layers
1043 if(zres >= rt_domain(did)%subsurface%properties%sldpth(k)*100.) then
1044 ! complete filling of a LSM soil layer if groundwater head > layer top
1046 ! gw2d(did)%qsgwrt(i,j) = (rt_domain(did)%subsurface%properties%sldpth(k) &
1047 ! * (rt_domain(did)%subsurface%grid_transform%smcmaxrt(i,j,k) - RT_DOMAIN(did)%subsurface%grid_transform%smcrt(i,j,k)) &
1048 ! + gw2d(did)%qsgwrt(i,j)) / gw2d(did)%dt
1050 rt_domain(did)%subsurface%grid_transform%smcrt(i,j,k) = RT_DOMAIN(did)%subsurface%grid_transform%smcmaxrt(i,j,k)
1052 zres = zres - rt_domain(did)%subsurface%properties%sldpth(k)*100.
1055 ! partial filling of a soil layer if not completely below groundwater head
1057 if(zres > (0.5 * rt_domain(did)%subsurface%properties%sldpth(k)*100.)) then
1059 frac = zres / (rt_domain(did)%subsurface%properties%sldpth(k) * 100.)
1062 ! gw2d(did)%qsgwrt(i,j) = (rt_domain(did)%subsurface%properties%sldpth(k) &
1063 ! * (rt_domain(did)%subsurface%grid_transform%smcmaxrt(i,j,k) - RT_DOMAIN(did)%subsurface%grid_transform%smcrt(i,j,k)) &
1064 ! * frac + gw2d(did)%qsgwrt(i,j)) / gw2d(did)%dt
1066 rt_domain(did)%subsurface%grid_transform%smcrt(i,j,k) = RT_DOMAIN(did)%subsurface%grid_transform%smcmaxrt(i,j,k) * frac
1077 ! qsgwrt < 0 -> downward flux
1078 ! qsgwrt > 0 -> upward flux
1080 ! TOcheck Step 3, adapt groundwater head (assuming not time lag for percolation / capillary rise flow)
1082 ! modify gw-head before gwstep call with respect to specific yield of the
1083 ! aquifer and the computed flux (qsgwrt)
1086 headChange = (-gw2d(did)%qdarcyRT) * gw2d(did)%dt / gw2d(did)%poros
1087 gw2d(did)%ho = gw2d(did)%ho + headChange
1089 end subroutine gwSoilFlux
1091 subroutine darcyGwSoil(Z, s, soil, q_darcy)
1095 INTEGER, INTENT (IN) :: soil ! soiltype
1097 REAL :: sig_a, sig_b, sig_c
1099 REAL, DIMENSION(9) :: k_para
1100 REAL, INTENT (IN) :: Z, s
1101 REAL, INTENT (OUT) :: q_darcy
1102 real :: beta,alpha,q_cap,b,ks,aep,c,q_grav,y,fac
1104 real, dimension(9,12) :: &
1105 k_soil = reshape((/&
1106 0.0778, 3.9939, 0.2913, 4.0801, 0.1386, 4.0500, -12.10, 0.3950, 1.0560,&
1107 0.0924, 4.8822, 0.2674, 3.8915, 0.1365, 4.3800, -09.00, 0.4100, 0.9380,&
1108 0.0367, 4.5259, 0.2446, 4.2849, 0.1208, 4.9000, -21.80, 0.4350, 0.2080,&
1109 0.0101, 3.6896, 0.2153, 4.2765, 0.0887, 5.3000, -78.60, 0.4850, 0.0432,&
1110 0.0101, 3.6896, 0.2153, 4.2765, 0.0887, 5.3000, -78.60, 0.4850, 0.0432,&
1111 0.0169, 2.9936, 0.2858, 4.3738, 0.1026, 5.3900, -47.80, 0.4510, 0.0417,&
1112 0.0271, 4.4743, 0.2587, 3.9055, 0.0920, 7.1200, -29.90, 0.4200, 0.0378,&
1113 0.0227, 4.3768, 0.2658, 3.8234, 0.0843, 7.7500, -35.60, 0.4770, 0.0102,&
1114 0.0127, 6.6836, 0.1725, 3.7512, 0.0703, 8.5200, -63.00, 0.4760, 0.0147,&
1115 0.0530, 9.2423, 0.1859, 3.3688, 0.0728, 10.400, -15.30, 0.4260, 0.0130,&
1116 0.0165, 5.3972, 0.2479, 3.5549, 0.0641, 10.400, -49.00, 0.4920, 0.0062,&
1117 0.0200, 6.0106, 0.2474, 3.4788, 0.0622, 11.400, -40.50, 0.4820, 0.0077/),(/9,12/))
1121 k_para = k_soil(:,soil)
1122 sig_a = 1 - exp( -1 * k_para(1) * Z)
1123 sig_b = k_para(2) * Z**k_para(3)
1124 sig_c = k_para(4) * exp( -1 * Z**k_para(5))
1125 y = sig_a/(1 + exp(sig_b * (s - sig_c))) !solving equation (20) in Boogart et al.
1132 q_grav = -1 * ks * s**c
1134 ! alp is constant from equation (13) of paper
1136 alpha = 1 + 1.5 / (beta - 1)
1137 q_cap = ks * alpha * (aep / Z)**beta
1140 q_darcy = y * q_cap + q_grav ![cm/min]
1142 ! limit for exteme gradients with q >> saturated hydraulic conductivity
1143 ! if(q_cap > ks) q_cap = ks
1144 ! if(q_grav < -ks) q_grav = -ks
1146 ! if(q_darcy > ks) q_darcy = ks
1147 ! if(q_darcy < ks) q_darcy = -ks
1151 q_darcy = q_darcy * fac
1153 q_grav = q_grav * fac
1155 !returns q_darcy in [m/s]
1157 end subroutine darcyGwSoil
1161 subroutine aggregateQsgw(did)
1167 integer, intent(in) :: did
1168 integer :: j,i, ixxRT, jyyRT, m,n
1172 do j=1,rt_domain(did)%jx
1173 do i=1,rt_domain(did)%ix
1177 do m=nlst(did)%aggfactRT-1,0,-1
1178 do n=nlst(did)%aggfactRT-1,0,-1
1181 ixxRT = i * nlst(did)%aggfactRT-n
1182 jyyRT = j * nlst(did)%aggfactRT-m
1186 if(left_id.ge.0) ixxRT=ixxRT+1
1187 if(down_id.ge.0) jyyRT=jyyRT+1
1189 agg = agg + gw2d(did)%qdarcyRT(ixxRT, jyyRT)
1193 gw2d(did)%qsgw(i,j) = agg/(nlst(did)%aggfactRT**2)
1199 end subroutine aggregateQsgw
1201 ! Parallel tridiagonal solver useful for domain decomposed ADI
1202 ! Author(s): Mike Lambert
1204 ! Institution: Lawrence Livermore National Laboratory
1205 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
1206 ! for solution of the steady state diffusion equation",
1207 ! Parallel Computing 23 (1997) 2041-2065
1208 ! Ported to MPI by Benjamin Fersch, Karlsruhe Institute of Technology (2013)
1211 subroutine parysolv1(c,b,r,ct,pid,z_pid, &
1212 xsps, zsps, xdns, zdns)
1216 integer, intent(in) :: XSPS, &
1221 real, dimension(ZSPS, XSPS), intent(inout) :: c, &
1224 parameter (CLK_PER = 6.66666667e-9)
1226 real, dimension(0:ZSPS+1, 0:XSPS+1), intent(inout) :: r
1228 real, dimension(XSPS,2) :: zn, zntmp
1230 real, dimension(XSPS) :: t1, t2, fac
1232 real :: clockdt, click
1233 real :: ct, ti, tf, dt
1235 integer :: pid, z_pid
1236 integer :: i, j, sndr_pid, msg_type, cnt, ackn
1237 integer :: sendReq, recvReq
1240 parameter (ZN_REC = 46)
1242 integer :: source, dest
1249 if (z_pid .eq. 1) then
1251 ! Load (ZSPS,j)th equations into passing arrays.
1253 zntmp(j,1) = b(ZSPS,j)
1254 zntmp(j,2) = r(ZSPS,j)
1262 ! ! Send (ZSPS,j)th equations.
1263 ! ! Receive (ZSPS+1,j)th equations.
1265 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1266 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1267 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1268 call mpi_wait(sendReq, mpp_status, ierr)
1269 call mpi_wait(recvReq, mpp_status, ierr)
1273 call add_dt(ct,tf,ti,dt)
1277 ! Backward elimination in (ZSPS,j)th equations to get
1279 fac(j) = 1./(1. - b(ZSPS,j)*zn(j,1))
1280 r(ZSPS,j) = (r(ZSPS,j)-b(ZSPS,j)*zn(j,2))*fac(j)
1281 ! Forward elimination in (ZSPS+1,j)th equations to get
1283 r(ZSPS+1,j) = zn(j,2) - zn(j,1)*r(ZSPS,j)
1284 ! Completion of backward elimination to get remaining unknowns.
1286 r(i,j) = r(i,j) - b(i,j)*r(ZSPS,j)
1290 else if (z_pid .le. ZDNS/2) then
1295 ! ! Receive (0,j)th equations.
1297 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1298 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1299 call mpi_wait(recvReq, mpp_status, ierr)
1303 call add_dt(ct,tf,ti,dt)
1306 ! Forward elimination in (j,1)th equations.
1308 fac(j) = 1./(1. - c(1,j)*zn(j,1))
1309 ! Check for singular matrix (debugging only)
1310 b(1,j) = b(1,j)*fac(j)
1311 r(1,j) = (r(1,j) - c(1,j)*zn(j,2))*fac(j)
1312 ! Forward elimination in (ZSPS,j)th equations.
1313 fac(j) = 1./(1. - c(ZSPS,j)*b(1,j))
1314 ! Check for singular matrix (debugging only)
1315 b(ZSPS,j) = b(ZSPS,j)*fac(j)
1316 r(ZSPS,j) = (r(ZSPS,j)-c(ZSPS,j)*r(1,j))*fac(j)
1317 ! Store (0,j)th equations for later recovery of r(0,j).
1320 ! Load (ZSPS,j)th equations into passing arrays.
1321 zntmp(j,1) = b(ZSPS,j)
1322 zntmp(j,2) = r(ZSPS,j)
1328 ! ! Send (ZSPS,j)th equations.
1329 ! ! Receive (ZSPS+1,j)th equations.
1331 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1332 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1333 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1334 call mpi_wait(sendReq, mpp_status, ierr)
1335 call mpi_wait(recvReq, mpp_status, ierr)
1338 call add_dt(ct,tf,ti,dt)
1342 ! Backward elimination in (ZSPS,j)th equations.
1343 fac(j) = 1./(1. - b(ZSPS,j)*zn(j,1))
1344 ! Check for singular matrix (debugging only)
1345 r(ZSPS,j) = (r(ZSPS,j) - b(ZSPS,j)*zn(j,2))*fac(j)
1346 ! Backward elimination in (ZSPS+1,j)th equations.
1347 r(ZSPS+1,j) = zn(j,2) - zn(j,1)*r(ZSPS,j)
1348 ! Backward elimination in (ZSPS,j)th equations.
1349 r(1,j) = r(1,j) - b(1,j)*r(ZSPS,j)
1350 ! Load (1,j)th equations into passing arrays.
1358 ! ! Send (1,j)th equations.
1362 call add_dt(ct,tf,ti,dt)
1365 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1366 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1369 ! Backward elimination in (0,j)th equations.
1370 r(0,j) = t2(j) - t1(j)*r(1,j)
1372 ! Completion of forward and backward elimination to get remaining
1374 r(i,j) = r(i,j) - b(i,j)*r(ZSPS,j) - c(i,j)*r(1,j)
1378 call mpi_wait(sendReq, mpp_status, ierr)
1381 else if (z_pid .lt. ZDNS) then
1386 ! ! Receive (ZSPS+1,j)th equations.
1388 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1389 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1390 call mpi_wait(recvReq, mpp_status, ierr)
1394 call add_dt(ct,tf,ti,dt)
1398 ! Backward elimination in (ZSPS,j)th equations.
1399 fac(j) = 1./(1. - b(ZSPS,j)*zn(j,1))
1400 ! Check for singular matrix (debugging only)
1401 c(ZSPS,j) = c(ZSPS,j)*fac(j)
1402 r(ZSPS,j) = (r(ZSPS,j)-b(ZSPS,j)*zn(j,2))*fac(j)
1403 ! Backward elimination in (1,j)th equations.
1404 fac(j) = 1./(1. - b(1,j)*c(ZSPS,j))
1405 ! Check for singular matrix (debugging only)
1406 c(1,j) = c(1,j)*fac(j)
1407 r(1,j) = (r(1,j) - b(1,j)*r(ZSPS,j))*fac(j)
1408 ! Store (ZSPS+1,j)th equations for later recovery of
1412 ! Load passing arrays with (1,j)th equations.
1420 ! ! Send (1,j)th equations.
1421 ! ! Receive (0,j)th equations.
1423 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1424 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1425 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1426 call mpi_wait(sendReq, mpp_status, ierr)
1427 call mpi_wait(recvReq, mpp_status, ierr)
1431 call add_dt(ct,tf,ti,dt)
1435 ! Forward elimination in (1,j)th equations
1436 fac(j) = 1./(1. - c(1,j)*zn(j,1))
1437 ! Check for singular matrix (debugging only)
1438 r(1,j) = (r(1,j) - c(1,j)*zn(j,2))*fac(j)
1439 ! Backward elimination in (0,j)th equations.
1440 r(0,j) = zn(j,2) - zn(j,1)*r(1,j)
1441 ! Forward elimination in (ZSPS,j)th equations.
1442 r(ZSPS,j) = r(ZSPS,j) - c(ZSPS,j)*r(1,j)
1443 ! Load (ZSPS,j)th equations into passing arrays.
1445 zntmp(j,2) = r(ZSPS,j)
1451 ! ! Send (ZSPS,j)th equations.
1453 call mpi_cart_shift(cartGridComm, rowshift, 1, source, dest, ierr)
1454 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1458 call add_dt(ct,tf,ti,dt)
1462 ! Forward elimination in (ZSPS+1,j)th equations to get
1464 r(ZSPS+1,j) = t2(j) - t1(j)*r(ZSPS,j)
1465 do 110 i = 2, ZSPS-1
1466 ! Completion of forward and backward elimination to get remaining unknowns.
1467 r(i,j) = r(i,j) - c(i,j)*r(1,j) - b(i,j)*r(ZSPS,j)
1471 call mpi_wait(sendReq, mpp_status, ierr)
1475 ! Load (1,j)th equations into passing arrays.
1484 ! ! Send (1,j)th equations.
1485 ! ! Receive (0,j)th equations.
1487 call mpi_cart_shift(cartGridComm, rowshift, -1, source, dest, ierr)
1488 call MPI_ISEND(zntmp, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, sendReq, ierr)
1489 call MPI_IRECV( zn, cnt, MPI_REAL, dest, ZN_REC, cartGridComm, recvReq, ierr)
1490 call mpi_wait(sendReq, mpp_status, ierr)
1491 call mpi_wait(recvReq, mpp_status, ierr)
1495 call add_dt(ct,tf,ti,dt)
1499 ! Forward elimination in (1,j)th equations to get r(1,j).
1500 fac(j) = 1./(1. - c(1,j)*zn(j,1))
1501 ! Check for singular matrix (debugging only)
1502 r(1,j) = (r(1,j) - c(1,j)*zn(j,2))*fac(j)
1503 ! Backward elimination in (0,j)th equations to get remaining unknowns.
1504 r(0,j) = zn(j,2) - zn(j,1)*r(1,j)
1506 ! Completion of forward elimination to get remaining unknowns.
1507 r(i,j) = r(i,j) - c(i,j)*r(1,j)
1517 ! Parallel tridiagonal solver useful for domain decomposed ADI
1518 ! Author(s): Mike Lambert
1520 ! Institution: Lawrence Livermore National Laboratory
1521 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
1522 ! for solution of the steady state diffusion equation",
1523 ! Parallel Computing 23 (1997) 2041-2065
1524 ! Ported to MPI by Benjamin Fersch, Karlsruhe Institute of Technology (2013)
1526 subroutine parxsolv1(c,b,r,ct,pid,x_pid, &
1527 xsps, zsps, xdns, zdns)
1531 integer, intent(in) :: XSPS, &
1536 real, dimension(ZSPS, XSPS), intent(inout) :: c, &
1540 real, dimension(0:ZSPS+1, 0:XSPS+1), intent(inout) :: r
1542 real, dimension(ZSPS,2) :: xn, xntmp
1545 parameter (XN_REC = 45)
1547 real, dimension(ZSPS) :: t1, t2, fac
1548 real :: clockdt, click
1549 real :: ct, ti, tf, dt
1551 integer :: pid, x_pid
1552 integer :: i, j, sndr_pid, msg_type, cnt, ackn
1553 integer :: sendReq, recvReq
1555 integer :: source, dest
1562 if (x_pid .eq. 1) then
1564 ! Load passing (i,XSPS)th equations into passing arrays.
1566 xntmp(i,1) = b(i,XSPS)
1567 xntmp(i,2) = r(i,XSPS)
1574 ! ! Send (i,XSPS)th equations.
1575 ! ! Receive (i,(XSPS + 1))th equations.
1577 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1578 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1579 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1580 call mpi_wait(sendReq, mpp_status, ierr)
1581 call mpi_wait(recvReq, mpp_status, ierr)
1585 call add_dt(ct,tf,ti,dt)
1589 ! Backward elimination in (i,XSPS)th equations to get
1591 fac(i) = 1./(1. - b(i,XSPS)*xn(i,1))
1592 r(i,XSPS) = (r(i,XSPS)-b(i,XSPS)*xn(i,2))*fac(i)
1593 ! Forward elimination in (i,XSPS+1)th equations to get
1595 r(i,XSPS+1) = xn(i,2) - xn(i,1)*r(i,XSPS)
1598 ! Completion of backward elimination to get remaining unknowns.
1601 r(i,j) = r(i,j) - b(i,j)*r(i,XSPS)
1604 else if (x_pid .le. XDNS/2) then
1610 ! ! Receive (i,0)th equations.
1612 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1613 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1614 call mpi_wait(recvReq, mpp_status, ierr)
1618 call add_dt(ct,tf,ti,dt)
1621 ! Forward elimination in (i,1)th equations of subdomain.
1623 fac(i) = 1./(1. - c(i,1)*xn(i,1))
1624 b(i,1) = b(i,1)*fac(i)
1625 r(i,1) = (r(i,1) - c(i,1)*xn(i,2))*fac(i)
1626 ! Forward elimination in (i,XSPS)th equations of subdomain.
1627 fac(i) = 1./(1. - c(i,XSPS)*b(i,1))
1628 b(i,XSPS) = b(i,XSPS)*fac(i)
1629 r(i,XSPS)=(r(i,XSPS)-c(i,XSPS)*r(i,1))*fac(i)
1630 ! Store (i,0)th equations for later recovery of r(i,0).
1633 ! Load (i,XSPS)th equations into passing arrays.
1634 xntmp(i,1) = b(i,XSPS)
1635 xntmp(i,2) = r(i,XSPS)
1642 ! ! Send (i,XSPS)th equations.
1643 ! ! Receive (i,(XSPS + 1))th equations.
1645 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1646 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1647 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1648 call mpi_wait(sendReq, mpp_status, ierr)
1649 call mpi_wait(recvReq, mpp_status, ierr)
1652 call add_dt(ct,tf,ti,dt)
1656 ! Backward elimination in (i,XSPS)th equations.
1657 fac(i) = 1./(1. - b(i,XSPS)*xn(i,1))
1658 r(i,XSPS) = (r(i,XSPS) - b(i,XSPS)*xn(i,2))*fac(i)
1659 ! Backward elimination in (i,XSPS+1)th equations.
1660 r(i,XSPS+1) = xn(i,2) - xn(i,1)*r(i,XSPS)
1661 ! Backward elimination in (i,1)th equations to get r(i,1).
1662 r(i,1) = r(i,1) - b(i,1)*r(i,XSPS)
1663 ! Load (i,1)th equations into passing array.
1672 ! ! Send (i,1)th equations.
1676 call add_dt(ct,tf,ti,dt)
1678 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1679 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1682 ! Backward elimination in (i,0)th equations.
1683 r(i,0) = t2(i) - t1(i)*r(i,1)
1686 ! Completion of forward and backward elimination for solution of
1690 r(i,j) = r(i,j) - b(i,j)*r(i,XSPS) - c(i,j)*r(i,1)
1693 call mpi_wait(sendReq, mpp_status, ierr)
1695 else if (x_pid .lt. XDNS) then
1701 ! ! Receive (i,XSPS+1)th equations.
1703 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1704 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1705 call mpi_wait(recvReq, mpp_status, ierr)
1709 call add_dt(ct,tf,ti,dt)
1713 ! Backward elimination in (i,XSPS)th equations.
1714 fac(i) = 1./(1. - b(i,XSPS)*xn(i,1))
1715 c(i,XSPS) = c(i,XSPS)*fac(i)
1716 r(i,XSPS) = (r(i,XSPS) - b(i,XSPS)*xn(i,2))*fac(i)
1717 ! Backward elimination in (i,1)th equations.
1718 fac(i) = 1./(1. - b(i,1)*c(i,XSPS))
1719 c(i,1) = c(i,1)*fac(i)
1720 r(i,1) = (r(i,1) - b(i,1)*r(i,XSPS))*fac(i)
1721 ! Store (i,XSPS+1)th equations for later recovery of r(i,XSPS+1).
1724 ! Load passing arrays with (i,1)th equations.
1733 ! ! Send (i,1)th equations.
1734 ! ! Receive (i,0)th equations.
1735 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1736 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1737 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1738 call mpi_wait(sendReq, mpp_status, ierr)
1739 call mpi_wait(recvReq, mpp_status, ierr)
1743 call add_dt(ct,tf,ti,dt)
1747 ! Forward elimination in (i,1)th equations
1748 fac(i) = 1./(1. - c(i,1)*xn(i,1))
1749 r(i,1) = (r(i,1) - c(i,1)*xn(i,2))*fac(i)
1750 ! Backward elimination in (i,0)th equations.
1751 r(i,0) = xn(i,2) - xn(i,1)*r(i,1)
1752 ! Forward elimination in (i,XSPS)th equations.
1753 r(i,XSPS) = r(i,XSPS) - c(i,XSPS)*r(i,1)
1754 ! Load (i,XSPS)th equations into passing arrays.
1756 xntmp(i,2) = r(i,XSPS)
1763 ! ! Send (i,XSPS)th equations.
1765 call mpi_cart_shift(cartGridComm, colshift, 1, source, dest, ierr)
1766 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1769 call add_dt(ct,tf,ti,dt)
1772 ! Forward elimination in (i,XSPS)th equations to get
1775 r(i,XSPS+1) = t2(i) - t1(i)*r(i,XSPS)
1778 ! Completion of forward and backward elimination to get remaining unknowns.
1779 do 110 j = 2, XSPS-1
1781 r(i,j) = r(i,j) - c(i,j)*r(i,1) - b(i,j)*r(i,XSPS)
1784 call mpi_wait(sendReq, mpp_status, ierr)
1788 ! Load (i,1)th equations into passing arrays.
1798 ! ! Send (i,1)th equations.
1799 ! ! Receive (i,0)th equations.
1801 call mpi_cart_shift(cartGridComm, colshift, -1, source, dest, ierr)
1802 call MPI_ISEND(xntmp, cnt, MPI_REAL, dest, XN_REC, cartGridComm, sendReq, ierr)
1803 call MPI_IRECV( xn, cnt, MPI_REAL, dest, XN_REC, cartGridComm, recvReq, ierr)
1804 call mpi_wait(sendReq, mpp_status, ierr)
1805 call mpi_wait(recvReq, mpp_status, ierr)
1809 call add_dt(ct,tf,ti,dt)
1813 ! Forward elimination in (i,1)th equations to get r(i,1).
1814 fac(i) = 1./(1. - c(i,1)*xn(i,1))
1815 r(i,1) = (r(i,1) - c(i,1)*xn(i,2))*fac(i)
1816 ! Backward elimination in (i,0)th equations to get r(i,0).
1817 r(i,0) = xn(i,2) - xn(i,1)*r(i,1)
1820 ! Completion of forward elimination to get remaining unknowns.
1823 r(i,j) = r(i,j) - c(i,j)*r(i,1)
1832 ! Parallel tridiagonal solver useful for domain decomposed ADI
1833 ! Author(s): Mike Lambert
1835 ! Institution: Lawrence Livermore National Laboratory
1836 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
1837 ! for solution of the steady state diffusion equation",
1838 ! Parallel Computing 23 (1997) 2041-2065
1840 subroutine sub_n_form(n_xs,n_zs,c,a,b,r,c2,b2,r2,wk,xfac,zfac, &
1847 ! c(,) -- subdiagonal elements of tridiagonal systems
1848 ! a(,) -- diagonal elements of tridiagonal systems
1849 ! b(,) -- superdiagonal elements of tridiagonal systems
1850 ! r(,) -- right-hand side elements of tridiagonal systems
1851 ! c2(,) -- front-leg elements of N-systems
1852 ! b2(,) -- back-leg elements of N-systems
1853 ! r2(,) -- right-hand side elements of N-systems
1854 ! wk(,) -- work array with same dimensions as a, b, c, etc.
1861 real r2(0:n_zs+1,0:n_xs+1)
1867 integer dpid,dn_subs,dir
1868 integer i, j, XDIR, ZDIR
1869 parameter (XDIR = 1, ZDIR = 2)
1871 if (dir .eq. XDIR) then
1873 ! Forward elimination of subdiagonal elements
1874 if (dpid .eq. 1) then
1879 r2(i,1) = r(i,1)*xfac(i)
1884 wk(i,j-1) = b(i,j-1)*xfac(i)
1885 xfac(i) = 1./(a(i,j) - c(i,j)*wk(i,j-1))
1887 r2(i,j) = (r(i,j) - c(i,j)*r2(i,j-1))*xfac(i)
1891 b2(i,n_xs) = b(i,n_xs)*xfac(i)
1898 c2(i,1) = c(i,1)*xfac(i)
1899 wk(i,1) = b(i,1)*xfac(i)
1900 r2(i,1) = r(i,1)*xfac(i)
1902 c2(i,2) = c(i,2)*xfac(i)
1903 r2(i,2) = r(i,2)*xfac(i)
1908 wk(i,j-1) = b(i,j-1)*xfac(i)
1909 xfac(i) = 1./(a(i,j) - c(i,j)*wk(i,j-1))
1910 c2(i,j) = -c(i,j)*c2(i,j-1)*xfac(i)
1911 r2(i,j) = (r(i,j) - c(i,j)*r2(i,j-1))*xfac(i)
1915 b2(i,n_xs) = b(i,n_xs)*xfac(i)
1920 ! Backward elimination of superdiagonal elements
1921 if (dpid .eq. dn_subs) then
1923 do 90 j = n_xs-1, 2, -1
1925 c2(i,j) = c2(i,j) - wk(i,j)*c2(i,j+1)
1927 r2(i,j) = r2(i,j) - wk(i,j)*r2(i,j+1)
1931 fac = 1./(1. - wk(i,1)*c2(i,2))
1932 c2(i,1) = c2(i,1)*fac
1934 r2(i,1) = (r2(i,1) - wk(i,1)*r2(i,2))*fac
1940 b2(i,n_xs-1) = wk(i,n_xs-1)
1943 do 120 j = n_xs-2, 2, -1
1945 c2(i,j) = c2(i,j) - wk(i,j)*c2(i,j+1)
1946 b2(i,j) = -wk(i,j)*b2(i,j+1)
1947 r2(i,j) = r2(i,j) - wk(i,j)*r2(i,j+1)
1950 ! If only 2 points in X-direction, do not execute these statements.
1951 if (n_xs .gt. 2) then
1953 fac = 1./(1. - wk(i,1)*c2(i,2))
1954 c2(i,1) = c2(i,1)*fac
1955 r2(i,1) = (r2(i,1) - wk(i,1)*r2(i,2))*fac
1956 b2(i,1) = -wk(i,1)*b2(i,2)*fac
1962 else if (dir .eq. ZDIR) then
1964 ! Forward elimination of subdiagonal elements
1965 if (dpid .eq. 1) then
1970 r2(1,j) = r(1,j)*zfac(j)
1975 wk(i-1,j) = b(i-1,j)*zfac(j)
1976 zfac(j) = 1./(a(i,j) - c(i,j)*wk(i-1,j))
1978 r2(i,j) = (r(i,j) - c(i,j)*r2(i-1,j))*zfac(j)
1982 b2(n_zs,j) = b(n_zs,j)*zfac(j)
1989 c2(1,j) = c(1,j)*zfac(j)
1990 wk(1,j) = b(1,j)*zfac(j)
1991 r2(1,j) = r(1,j)*zfac(j)
1993 c2(2,j) = c(2,j)*zfac(j)
1994 r2(2,j) = r(2,j)*zfac(j)
1999 wk(i-1,j) = b(i-1,j)*zfac(j)
2000 zfac(j) = 1./(a(i,j) - c(i,j)*wk(i-1,j))
2001 c2(i,j) = -c(i,j)*c2(i-1,j)*zfac(j)
2002 r2(i,j) = (r(i,j) - c(i,j)*r2(i-1,j))*zfac(j)
2006 b2(n_zs,j) = b(n_zs,j)*zfac(j)
2011 ! Backward elimination of superdiagonal elements
2012 if (dpid .eq. dn_subs) then
2015 do 220 i = n_zs - 1, 2, -1
2016 c2(i,j) = c2(i,j) - wk(i,j)*c2(i+1,j)
2018 r2(i,j) = r2(i,j) - wk(i,j)*r2(i+1,j)
2022 fac = 1./(1. - wk(1,j)*c2(2,j))
2023 c2(1,j) = c2(1,j)*fac
2025 r2(1,j) = (r2(1,j) - wk(1,j)*r2(2,j))*fac
2031 b2(n_zs-1,j) = wk(n_zs-1,j)
2035 do 250 i = n_zs - 2, 2, -1
2036 c2(i,j) = c2(i,j) - wk(i,j)*c2(i+1,j)
2037 b2(i,j) = -wk(i,j)*b2(i+1,j)
2038 r2(i,j) = r2(i,j) - wk(i,j)*r2(i+1,j)
2041 ! If only 2 points in Z-direction, do not execute these statements.
2042 if (n_zs .gt. 2) then
2044 fac = 1./(1. - wk(1,j)*c2(2,j))
2045 c2(1,j) = c2(1,j)*fac
2046 r2(1,j) = (r2(1,j) - wk(1,j)*r2(2,j))*fac
2047 b2(1,j) = -wk(1,j)*b2(2,j)*fac
2053 ! Announce bad direction specifier (debugging only)
2055 ! write(*,*) 'sub_n_form: What direction?'
2063 ! Tridiagonal solver useful for domain decomposed ADI
2064 ! Author(s): Mike Lambert
2066 ! Institution: Lawrence Livermore National Laboratory
2067 ! Publication: Lambert, Rodrigue, and Hewett, "A parallel DSDADI method
2068 ! for solution of the steady state diffusion equation",
2069 ! Parallel Computing 23 (1997) 2041-2065
2071 subroutine sub_tri_solv(n_xs,n_zs,c,a,b,r,x,wk,xfac,zfac,dir)
2077 ! c(,) -- subdiagonal elements of tridiagonal systems
2078 ! a(,) -- diagonal elements of tridiagonal systems
2079 ! b(,) -- superdiagonal elements of tridiagonal systems
2080 ! r(,) -- right-hand side elements of tridiagonal systems
2082 ! wk(,) -- work array w/ same dimensions as c, a, b, etc.
2088 real x(0:n_zs+1,0:n_xs+1)
2094 integer i,j,XDIR,ZDIR
2096 parameter (XDIR = 1, ZDIR = 2)
2098 if (dir .eq. XDIR) then
2101 ! Check for need to pivot (debugging only)
2103 x(i,1) = r(i,1)*xfac(i)
2106 ! Forward subdiagonal elimination
2109 wk(i,j-1) = b(i,j-1)*xfac(i)
2110 xfac(i) = 1./(a(i,j) - c(i,j)*wk(i,j-1))
2111 ! Check for need to pivot (debugging only)
2112 x(i,j) = (r(i,j) - c(i,j)*x(i,j-1))*xfac(i)
2116 do 30 j = n_xs - 1, 1, -1
2118 x(i,j) = x(i,j) - wk(i,j)*x(i,j+1)
2122 else if (dir .eq. ZDIR) then
2125 ! Check for need to pivot (debugging only)
2127 x(1,j) = r(1,j)*zfac(j)
2130 ! Forward subdiagonal elimination
2133 wk(i-1,j) = b(i-1,j)*zfac(j)
2134 zfac(j) = 1./(a(i,j) - c(i,j)*wk(i-1,j))
2135 ! Check for need to pivot (debugging only)
2136 x(i,j) = (r(i,j) - c(i,j)*x(i-1,j))*zfac(j)
2142 do i = n_zs - 1, 1, -1
2143 x(i,j) = x(i,j) - wk(i,j)*x(i+1,j)
2147 ! Announce bad direction specifier (debugging only)
2149 ! write(*,*) 'sub_tri_solv: What direction?'
2157 end module module_gw_gw2d