XBeach
|
00001 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00002 ! Copyright (C) 2007 UNESCO-IHE, WL|Delft Hydraulics and Delft University ! 00003 ! Dano Roelvink, Ap van Dongeren, Ad Reniers, Jamie Lescinski, ! 00004 ! Jaap van Thiel de Vries, Robert McCall ! 00005 ! ! 00006 ! d.roelvink@unesco-ihe.org ! 00007 ! UNESCO-IHE Institute for Water Education ! 00008 ! P.O. Box 3015 ! 00009 ! 2601 DA Delft ! 00010 ! The Netherlands ! 00011 ! ! 00012 ! This library is free software; you can redistribute it and/or ! 00013 ! modify it under the terms of the GNU Lesser General Public ! 00014 ! License as published by the Free Software Foundation; either ! 00015 ! version 2.1 of the License, or (at your option) any later version. ! 00016 ! ! 00017 ! This library is distributed in the hope that it will be useful, ! 00018 ! but WITHOUT ANY WARRANTY; without even the implied warranty of ! 00019 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 00020 ! Lesser General Public License for more details. ! 00021 ! ! 00022 ! You should have received a copy of the GNU Lesser General Public ! 00023 ! License along with this library; if not, write to the Free Software ! 00024 ! Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ! 00025 ! USA ! 00026 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00027 module groundwaterflow 00028 implicit none 00029 save 00030 private ! set private default 00031 ! set these public to users of groundwater module 00032 public gw_init 00033 public gw_bc 00034 public gwflow 00035 00036 contains 00037 00038 00039 00040 subroutine gw_init(s,par) 00041 use params, only: parameters 00042 use xmpi_module 00043 use spaceparams 00044 00045 IMPLICIT NONE 00046 00047 type(parameters) :: par 00048 type(spacepars) :: s 00049 00050 integer :: i,j 00051 00052 if(.not. xmaster) return ! Robert: change in way called from libxbeach 00053 00054 allocate (s%gwhead(s%nx+1,s%ny+1)) 00055 allocate (s%gwheadb(s%nx+1,s%ny+1)) 00056 allocate (s%gwlevel(s%nx+1,s%ny+1)) 00057 allocate (s%gwheight(s%nx+1,s%ny+1)) 00058 allocate (s%gwu(s%nx+1,s%ny+1)) 00059 allocate (s%gwv(s%nx+1,s%ny+1)) 00060 allocate (s%gwqx(s%nx+1,s%ny+1)) 00061 allocate (s%gwqy(s%nx+1,s%ny+1)) 00062 allocate (s%gww(s%nx+1,s%ny+1)) 00063 allocate (s%infil(s%nx+1,s%ny+1)) 00064 allocate (s%gwbottom(s%nx+1,s%ny+1)) 00065 allocate (s%dinfil(s%nx+1,s%ny+1)) 00066 allocate (s%gw0back(2,s%ny+1)) 00067 allocate (s%gwcurv(s%nx+1,s%ny+1)) 00068 allocate (s%Kx(s%nx+1,s%ny+1)) 00069 allocate (s%Ky(s%nx+1,s%ny+1)) 00070 allocate (s%Kz(s%nx+1,s%ny+1)) 00071 allocate (s%Kzinf(s%nx+1,s%ny+1)) 00072 00073 s%gww=0.d0 00074 s%infil = 0.d0 00075 00076 if (par%gwflow==1) then 00077 if (par%aquiferbotfile==' ') then ! Not a filename 00078 s%gwbottom=par%aquiferbot 00079 else 00080 open(31,file=trim(par%aquiferbotfile)) 00081 do j=1,s%ny+1 00082 read(31,*)(s%gwbottom(i,j),i=1,s%nx+1) 00083 end do 00084 close(31) 00085 endif 00086 00087 if (par%gw0file==' ') then ! Not a filename 00088 s%gwhead=par%gw0 00089 else 00090 open(31,file=trim(par%gw0file)) 00091 do j=1,s%ny+1 00092 read(31,*)(s%gwhead(i,j),i=1,s%nx+1) 00093 end do 00094 close(31) 00095 endif 00096 if (xmpi_istop) then 00097 s%gwbottom(1,:) = s%gwbottom(2,:) 00098 endif 00099 if (xmpi_isbot) then 00100 s%gwbottom(s%nx+1,:) = s%gwbottom(s%nx,:) 00101 endif 00102 if (xmpi_isleft .and. s%ny>0) then 00103 s%gwbottom(:,1) = s%gwbottom(:,2) 00104 endif 00105 if (xmpi_isright .and. s%ny>0) then 00106 s%gwbottom(:,s%ny+1) = s%gwbottom(:,s%ny) 00107 endif 00108 00109 s%gwbottom = min(s%gwbottom,s%zb) 00110 00111 s%gwhead=max(s%gwhead,s%gwbottom) 00112 s%gw0back=s%gwhead(s%nx:s%nx+1,:) 00113 00114 s%gwlevel=min(s%zb,s%gwhead) 00115 s%gwlevel=max(s%gwlevel,s%gwbottom) !+par%eps) 00116 00117 s%gwheight=s%gwlevel-s%gwbottom 00118 00119 s%gwu=0.d0 00120 s%gwv=0.d0 00121 s%gww=0.d0 00122 s%gwqx = 0.d0 00123 s%gwqy = 0.d0 00124 s%gwcurv=0.d0 00125 s%infil = 0.d0 00126 s%dinfil=max(par%dwetlayer/3.d0,0.02) ! Centroid of area influenced instantly by free surface level lies at dwetlayer/3 00127 endif 00128 end subroutine gw_init 00129 00130 subroutine gw_bc(s,par) 00131 use params, only: parameters 00132 use xmpi_module 00133 use spaceparams 00134 use paramsconst 00135 00136 IMPLICIT NONE 00137 00138 type(parameters) :: par 00139 type(spacepars) :: s 00140 00141 00142 s%gwbottom=min(s%gwbottom,s%zb) !-par%eps) 00143 00144 if(xmpi_istop) then 00145 ! s%gwhead(1,:)=s%zs0(1,:) 00146 s%gwhead(1,:)=s%gwhead(2,:) 00147 s%gwbottom(1,:) = s%gwbottom(2,:) 00148 endif 00149 if (xmpi_isbot) then 00150 if (par%tideloc==4 .or. (par%tideloc==2 .and. par%paulrevere==PAULREVERE_LAND)) then 00151 ! s%gwhead(s%nx+1,:)=s%zs0(s%nx+1,:) 00152 s%gwhead(s%nx+1,:)=s%gwhead(s%nx,:) 00153 else 00154 s%gwhead(s%nx+1,:)=s%gw0back(2,:) 00155 endif 00156 s%gwbottom(s%nx+1,:) = s%gwbottom(s%nx,:) 00157 endif 00158 if (xmpi_isleft .and. s%ny>0) then 00159 s%gwbottom(:,1) = s%gwbottom(:,2) 00160 s%gwhead(:,1)=s%gwhead(:,2) 00161 s%gwlevel(:,1)=s%gwlevel(:,2) 00162 endif 00163 if (xmpi_isright .and. s%ny>0) then 00164 s%gwbottom(:,s%ny+1) = s%gwbottom(:,s%ny) 00165 s%gwhead(:,s%ny+1)=s%gwhead(:,s%ny) 00166 s%gwlevel(:,s%ny+1)=s%gwlevel(:,s%ny) 00167 endif 00168 00169 #ifdef USEMPI 00170 call xmpi_shift_ee(s%gwhead) 00171 call xmpi_shift_ee(s%gwlevel) 00172 #endif 00173 if(xmpi_istop) then 00174 s%gwlevel(1,:)=min(s%gwhead(1,:),s%zb(1,:)) 00175 endif 00176 if (xmpi_isbot) then 00177 s%gwlevel(s%nx+1,:)=min(s%gwhead(s%nx+1,:),s%zb(s%nx+1,:)) 00178 endif 00179 00180 end subroutine gw_bc 00181 00182 subroutine gwflow(s,par) 00183 00184 use params, only: parameters 00185 use xmpi_module 00186 use spaceparams 00187 use constants, only: pi 00188 use paramsconst 00189 00190 IMPLICIT NONE 00191 00192 type(parameters) :: par 00193 type(spacepars),target :: s 00194 00195 ! internal variables 00196 integer :: i,j 00197 integer :: incl 00198 integer,parameter :: maxiter = 50 00199 real*8 :: dzr,wdt 00200 real*8,dimension(:,:),allocatable,save :: gwhu,gwhv,gwheadtop 00201 real*8,dimension(:,:),allocatable,save :: Kx,Ky,Kz,Kzinf 00202 real*8,dimension(:,:),allocatable,save :: Kxupd,Kyupd,Kzupd 00203 logical,dimension(:,:),allocatable,save :: connected 00204 real*8,dimension(:,:),allocatable,save :: fracdt 00205 real*8,dimension(:,:),allocatable,save :: zsupd,ratio 00206 real*8,dimension(:,:),allocatable,save :: dynpresupd 00207 real*8,dimension(:,:),allocatable,save :: infiluncon 00208 ! wwvv changed allocatable into pointer: 00209 ! wwvv see also later in this file 00210 real*8,dimension(:,:),pointer,save :: infilcon 00211 real*8,dimension(:,:),allocatable,save :: infilhorgw,infilhorsw 00212 real*8,dimension(:,:),allocatable,save :: gwumean 00213 real*8 :: factime 00214 logical :: initial 00215 real*8,save :: connectcrit 00216 00217 00218 initial = .false. 00219 00220 ! allocate variables 00221 if (.not. allocated(gwhu)) then 00222 allocate(gwhu(1:s%nx+1,1:s%ny+1)) 00223 allocate(gwhv(1:s%nx+1,1:s%ny+1)) 00224 allocate(gwheadtop(1:s%nx+1,1:s%ny+1)) 00225 00226 allocate(Kx(1:s%nx+1,1:s%ny+1)) 00227 allocate(Ky(1:s%nx+1,1:s%ny+1)) 00228 allocate(Kz(1:s%nx+1,1:s%ny+1)) 00229 allocate(Kzinf(1:s%nx+1,1:s%ny+1)) 00230 allocate(Kxupd(1:s%nx+1,1:s%ny+1)) 00231 allocate(Kyupd(1:s%nx+1,1:s%ny+1)) 00232 allocate(Kzupd(1:s%nx+1,1:s%ny+1)) 00233 00234 allocate(connected(1:s%nx+1,1:s%ny+1)) 00235 allocate(fracdt(1:s%nx+1,1:s%ny+1)) 00236 allocate(zsupd(1:s%nx+1,1:s%ny+1)) 00237 allocate(ratio(1:s%nx+1,1:s%ny+1)) 00238 00239 allocate(dynpresupd(1:s%nx+1,1:s%ny+1)) 00240 00241 allocate(infiluncon(1:s%nx+1,1:s%ny+1)) 00242 allocate(infilcon(1:s%nx+1,1:s%ny+1)) 00243 allocate(infilhorgw(1:s%nx+1,1:s%ny+1)) 00244 allocate(infilhorsw(1:s%nx+1,1:s%ny+1)) 00245 allocate(gwumean(1:s%nx+1,1:s%ny+1)) 00246 00247 ! initialise variables 00248 Kx = par%kx 00249 Ky = par%ky 00250 Kz = par%kz 00251 Kzinf = par%kz 00252 00253 Kxupd = Kx 00254 Kyupd = Ky 00255 Kzupd = Kz 00256 00257 infiluncon = 0.d0 00258 infilcon = 0.d0 00259 gwumean = 0.d0 00260 00261 dynpresupd = 0.d0 00262 00263 gwhu = 0.d0 00264 gwhv = 0.d0 00265 00266 initial = .true. 00267 if (par%gwnonh==0) then 00268 connectcrit = par%dwetlayer 00269 else 00270 connectcrit = par%eps 00271 endif 00272 00273 ratio = gw_calculate_smoothwetlayer(s,par%dwetlayer,par%px) 00274 endif 00275 ! 00276 ! Definition of horizontal groundwater velocity: 00277 ! Because there is not simple way of measuring flow in pores, Darcy relates to the 00278 ! flow velocity through the ground in terms of surface water (not pore water). 00279 ! Therefore, after the flux has been calculated the groundwater level change is 00280 ! divided by the porosity to get changes in terms of pore water. 00281 ! 00282 ! Definition of vertical groundwater/surface water exchange: 00283 ! infil is defined positive from sea to groundwater, gww is defined positive up 00284 ! (from groundwater to sea!). Both infil and gww are in volumes of surface water 00285 ! (not pore water). gwu and gwv are also in terms of surface water volume. 00286 ! 00287 ! Initialize 00288 s%gww = 0.d0 00289 s%infil = 0.d0 00290 infiluncon = 0.d0 00291 infilcon = 0.d0 00292 infilhorgw = 0.d0 00293 infilhorsw = 0.d0 00294 fracdt = 0.d0 00295 ! 00296 ! If using dynamic pressure (nonh==1), very short wave lengths mess things 00297 ! up because they are not resolved properly in the nonh pressure solver. 00298 ! To surpress this, carry out pressure averaging over time scale ~ 1/4 Trep 00299 if (par%wavemodel==WAVEMODEL_NONH) then 00300 factime = min(4*par%dt/par%Trep,1.d0) 00301 dynpresupd = (1-factime) * dynpresupd + factime * s%pres 00302 endif 00303 ! 00304 ! Infiltration and exfiltration are handled separately for places where the 00305 ! groundwater and surface water are connected (Poisson equation), and where 00306 ! they are disconnected (swash infiltration, seepage). "Connected" is set 00307 ! by the difference between the groundwater level and the bed level, and a 00308 ! numerical constant for stability 00309 where(s%wetz==1 .and. s%zb-s%gwlevel<connectcrit) 00310 connected = .true. 00311 elsewhere 00312 connected = .false. 00313 endwhere 00314 ! 00315 ! Handle infiltration in unconnected cells. Some cells may be 00316 ! unconnected for only part of the timestep, therefore a fraction 00317 ! of timestep is returned which was required to reach connection 00318 if (par%gwnonh==1) then 00319 call gw_unconnected_infil(s,par,Kzinf,connected,fracdt,infiluncon) 00320 ! where ((.not. connected) .and. (gwlevel>zb)) 00321 ! infiluncon = infiluncon - (gwlevel-zb)/par%dt*par%por 00322 ! fracdt = 1.d0 00323 ! endwhere 00324 where (s%gwlevel>s%zb) 00325 infiluncon = infiluncon - (s%gwlevel-s%zb)/par%dt*par%por 00326 endwhere 00327 endif 00328 ! 00329 ! 00330 ! Update groundwater level and water surface level to account for 00331 ! infiltration and exfiltration effects. Note infil is avarage 00332 ! infiltration rate over whole timestep 00333 s%gwlevel = s%gwlevel+par%dt*infiluncon/par%por 00334 zsupd = s%zs-par%dt*infiluncon 00335 ! 00336 ! Recalculate connected property, this is needed further on in the code 00337 where(zsupd-s%zb>=par%eps .and. s%zb-s%gwlevel<connectcrit) 00338 connected = .true. 00339 elsewhere 00340 connected = .false. 00341 endwhere 00342 ! 00343 ! Thickness of groundwater layer 00344 s%gwheight=s%gwlevel-s%gwbottom 00345 ! 00346 ! Determine intermediate aquifer depths (upwind scheme) 00347 call gw_calculate_interfaceheight(s,gwhu,gwhv,initial) 00348 ! 00349 ! Calculate head smoothing function over dwetlayer 00350 ratio = gw_calculate_smoothwetlayer(s,par%dwetlayer,par%px) 00351 ! 00352 ! Calculate top boundary condition for head (pressure on groundwater 00353 ! from surface water, or atmospheric pressure when dry). Takes into 00354 ! account a transition layer, specified by user to smooth transition 00355 ! from surface water head to atmospheric head 00356 if (par%wavemodel==WAVEMODEL_NONH) then 00357 gwheadtop = gwCalculateHeadTop(s%nx,s%ny,zsupd,s%gwlevel,s%wetz,ratio,1,par%g,dynpresupd) 00358 else 00359 gwheadtop = gwCalculateHeadTop(s%nx,s%ny,zsupd,s%gwlevel,s%wetz,ratio,0,par%g,dynpresupd) 00360 endif 00361 ! 00362 ! Compute groundwater head in cell centres 00363 ! In case of hydrostatic this is the same as the surface water head, 00364 ! or groundwater level. In order to ensure small errors do not explode 00365 ! minimum time averaging is done. 00366 ! In case of non-hydrostatic computations, the head is solved by the 00367 ! Poisson solver. In the case of a turbulent/modflow groundwater scheme 00368 ! the solver is forced using the estimate of the hydraulic conductivity 00369 ! from the previous time step. The estimate from the previous time step 00370 ! is also used to compute velocities (else no convervation of mass). The 00371 ! computation of the velocity also returns a new update of the hydraulic 00372 ! conductivity to be used in the next time step 00373 if (par%gwnonh == 0) then 00374 ! hydrostatic pressure assumption, with time delay required for 00375 ! stability 00376 ! factime = min(par%dt/0.2d0,1.d0) 00377 ! gwhead = (1.d0-factime)*gwhead + factime*gwheadtop 00378 s%gwhead = (s%gwhead + gwheadtop)/2 00379 else 00380 ! non-hydrostatic pressure, solve using Poisson solver. Kxupd is the 00381 ! updated hydraulic conductivity from the previous time step 00382 call gw_solver(par,s,gwheadtop,Kxupd,Kyupd,Kzupd,gwhu,gwhv,fracdt) 00383 endif 00384 ! 00385 ! 00386 ! Calculate groundwater velocities 00387 ! We use Kxupd input which is the same value as sent into the Poisson solver in 00388 ! the previous command. In the case of the non-hydrostatic solver, we must force 00389 ! the computation of the velocities to use the hydraulic conductivity estimate 00390 ! put into the Poisson solver. In practice this is only important is the hydraulic 00391 ! conductivity varies due to the turbulent/modflow scheme. 00392 ! 00393 ! Input Kx is the basic initial hydaulic conductivity 00394 ! Input Kxupd is the updated hydraulic conductivity from the previous time step 00395 ! used in the Poisson solver 00396 ! Output Kxupd is the new updated hydraulic conductivity for the next time step 00397 call gw_calculate_velocities(s,par,fracdt,s%gwu,s%gwv,s%gww,Kx,Ky,Kz,Kxupd,Kyupd,Kzupd) 00398 ! 00399 ! 00400 ! For next time step do some smoothing of Kx,Ky,Kx 00401 do j=1,s%ny+1 00402 do i=1,s%nx+1 00403 incl = min(i+3,s%nx+1)-max(1,i-3)+1 00404 Kx(i,j) = sum(Kxupd(max(1,i-3):min(i+3,s%nx+1),j))/incl 00405 Kz(i,j) = sum(Kzupd(max(1,i-3):min(i+3,s%nx+1),j))/incl 00406 Ky(i,j) = sum(Kyupd(max(1,i-3):min(i+3,s%nx+1),j))/incl 00407 enddo 00408 enddo 00409 Kxupd = Kx 00410 Kzupd = Kz 00411 Kyupd = Ky 00412 s%Kx = Kx 00413 s%Ky = Ky 00414 s%Kz = Kz 00415 Kx = par%kx 00416 Ky = par%ky 00417 Kz = par%kz 00418 s%Kzinf = Kzinf 00419 ! 00420 ! 00421 ! Calculate horizontal fluxes 00422 s%gwqx=s%gwu*gwhu 00423 s%gwqy=s%gwv*gwhv 00424 ! 00425 ! 00426 ! Stop cells from drying up 00427 if (s%ny>0) then 00428 do i=2,s%nx 00429 do j=2,s%ny 00430 if (s%gwlevel(i,j)<=s%gwbottom(i,j)+par%eps) then 00431 s%gwqx(i,j) = min(s%gwqx(i,j),0.d0) ! let no water out, only in 00432 s%gwqx(i-1,j) = max(s%gwqx(i-1,j),0.d0) ! let no water out, only in 00433 s%gwqy(i,j) = min(s%gwqy(i,j),0.d0) ! let no water out, only in 00434 s%gwqy(i,j-1) = max(s%gwqy(i,j-1),0.d0) ! let no water out, only in 00435 endif 00436 enddo 00437 enddo 00438 else 00439 do i=2,s%nx 00440 if (s%gwlevel(i,1)<=s%gwbottom(i,1)+par%eps) then 00441 s%gwqx(i,1) = min(s%gwqx(i,1),0.d0) ! let no water out, only in 00442 s%gwqx(i-1,1) = max(s%gwqx(i-1,1),0.d0) ! let no water out, only in 00443 endif 00444 enddo 00445 endif 00446 ! 00447 ! 00448 ! Force continuity, where gww is computed for hydrostatic computation and 00449 ! gww strictly enforced (no roundoff errors) for nonhydrostatic computation 00450 if (s%ny>2) then 00451 do j=2,s%ny 00452 do i=2,s%nx 00453 s%gww(i,j) = (-s%gwqx(i,j)*s%dnu(i,j)+s%gwqx(i-1,j)*s%dnu(i-1,j) & 00454 -s%gwqy(i,j)*s%dsv(i,j)+s%gwqy(i,j-1)*s%dsv(i,j-1))*s%dsdnzi(i,j) 00455 enddo 00456 enddo 00457 else 00458 if (s%ny>0) then 00459 do i=2,s%nx 00460 s%gww(i,2) = (-s%gwqx(i,2)+s%gwqx(i-1,2))/s%dsz(i,2) 00461 enddo 00462 s%gww(:,1) = s%gww(:,2) 00463 s%gww(:,3) = s%gww(:,2) 00464 else 00465 do i=2,s%nx 00466 s%gww(i,1) = (-s%gwqx(i,1)+s%gwqx(i-1,1))/s%dsz(i,1) 00467 enddo 00468 endif 00469 endif 00470 ! 00471 ! 00472 ! updating groundwater level is complicated: 00473 ! - in sections that are unconnected : dz/dt = -w/por == grad(qx,qy)/por 00474 ! - in sections that are connected: 00475 ! if w > 0 (exfiltration) : dz/dt = 0 (rise until gwlevel == zb, remainder is 00476 ! sent to zs) 00477 ! if w < 0 (infiltration) : dz/dt = 0 (unless available zs is less than w*dt, 00478 ! then drop water level on remainder) 00479 ! 00480 if (par%gwnonh==1) then 00481 ! non-hydrostatic computation 00482 do j=min(2,s%ny+1),max(s%ny,1) 00483 do i=2,s%nx 00484 ! exfiltration terms, same for connected and unconnected cells 00485 if (s%gww(i,j)>0.d0) then 00486 if (connected(i,j)) then 00487 dzr = max(s%zb(i,j)-s%gwlevel(i,j),0.d0) 00488 wdt = s%gww(i,j)*par%dt/par%por 00489 if (wdt>=dzr) then 00490 infilcon(i,j) = -s%gww(i,j)*(1.d0-dzr/wdt) 00491 else 00492 ! nothing 00493 endif 00494 endif 00495 ! connected infiltration terms, unconnected cells already computed 00496 ! infiltration at the start of the groundwater flow subroutine 00497 elseif (s%gww(i,j)<0.d0) then 00498 if (connected(i,j)) then 00499 dzr = max(s%zs(i,j)-s%zb(i,j)-par%eps,0.d0) 00500 wdt = -s%gww(i,j)*par%dt 00501 if (wdt>=dzr) then 00502 infilcon(i,j) = -s%gww(i,j)*(dzr/wdt) 00503 else 00504 infilcon(i,j) = -s%gww(i,j) 00505 endif 00506 endif 00507 else 00508 infilcon(i,j) = 0.d0 00509 endif 00510 enddo 00511 enddo 00512 else 00513 ! hydrostatic computation 00514 where(s%wetz==0) 00515 s%dinfil=par%dwetlayer/3.d0 ! Centroid of area influenced instantly by free surface level lies at dwetlayer/3 00516 elsewhere 00517 s%dinfil=min(s%dinfil,s%zb-s%gwlevel) 00518 s%dinfil=max(s%dinfil,par%dwetlayer/3.d0) 00519 endwhere 00520 ! wwvv since gw_calculate_hydrostatic_w returns a pointer: 00521 ! wwvv changed '=' into '=>' 00522 ! wwvv see also the declaration of infilcon 00523 infilcon => gw_calculate_hydrostatic_w(s,par,ratio) 00524 where (infilcon*par%dt>s%hh-par%eps) 00525 infilcon=(s%hh-par%eps)/par%dt 00526 endwhere 00527 s%dinfil=s%dinfil+infilcon*par%dt/par%por 00528 if (par%gwhorinfil==1) then 00529 call gw_horizontal_infil_exfil(s,par,infilhorgw,infilhorsw,Kx,dynpresupd) 00530 endif 00531 endif 00532 ! Compute new water level 00533 s%gwlevel = s%gwlevel + (s%gww+infilcon+infilhorgw)*par%dt/par%por 00534 ! 00535 ! In case of hydrostatic approach, try to fix the connected cells 00536 00537 ! 00538 ! Update total infiltration contribution 00539 s%infil = infiluncon+infilcon+infilhorsw 00540 ! 00541 ! Model boundaries 00542 ! Robert: check if all these are actually needed 00543 #ifdef USEMPI 00544 call xmpi_shift_ee(s%gwlevel) 00545 call xmpi_shift_ee(s%gwhead) 00546 call xmpi_shift_ee(s%gwcurv) 00547 #endif 00548 if (xmpi_istop) then 00549 s%gwlevel(1,:) = s%gwlevel(2,:) 00550 s%gwhead(1,:) = s%gwhead(2,:) 00551 s%gwcurv(1,:) = s%gwcurv(2,:) 00552 s%gwbottom(1,:) = s%gwbottom(2,:) 00553 s%gww(1,:) = s%gww(2,:) 00554 endif 00555 if (xmpi_isbot) then 00556 s%gwlevel(s%nx+1,:) = s%gwlevel(s%nx,:) 00557 s%gwhead(s%nx+1,:) = s%gwhead(s%nx,:) 00558 s%gwcurv(s%nx+1,:) = s%gwcurv(s%nx,:) 00559 s%gwbottom(s%nx+1,:) = s%gwbottom(s%nx,:) 00560 s%gww(s%nx+1,:) = s%gww(s%nx,:) 00561 endif 00562 if (xmpi_isleft .and. s%ny>0) then 00563 s%gwlevel(:,1) = s%gwlevel(:,2) 00564 s%gwhead(:,1) = s%gwhead(:,2) 00565 s%gwcurv(:,1) = s%gwcurv(:,2) 00566 s%gwbottom(:,1) = s%gwbottom(:,2) 00567 s%gww(:,1) = s%gww(:,2) 00568 endif 00569 if (xmpi_isright .and. s%ny>0) then 00570 s%gwlevel(:,s%ny+1) = s%gwlevel(:,s%ny) 00571 s%gwhead(:,s%ny+1) = s%gwhead(:,s%ny) 00572 s%gwcurv(:,s%ny+1) = s%gwcurv(:,s%ny) 00573 s%gwbottom(:,s%ny+1) = s%gwbottom(:,s%ny) 00574 s%gww(:,s%ny+1) = s%gww(:,s%ny) 00575 endif 00576 ! 00577 ! output pressure head at bottom 00578 ! 00579 s%gwheadb = gwCalculateHeadBottom(s%gwcurv,gwheadtop,s%gwheight,s%nx,s%ny,par%gwheadmodel) 00580 s%gwheadb(1,:) = s%gwheadb(2,:) 00581 s%gwheadb(s%nx+1,:) = s%gwheadb(s%nx,:) 00582 end subroutine gwflow 00583 00584 subroutine gw_unconnected_infil(s,par,Kzinf,connected,fracdt,infil) 00585 use params, only: parameters 00586 use xmpi_module 00587 use spaceparamsdef 00588 use paramsconst 00589 00590 IMPLICIT NONE 00591 00592 type(parameters),intent(in) :: par 00593 type(spacepars) :: s 00594 real*8,dimension(s%nx+1,s%ny+1),intent(inout):: Kzinf 00595 logical,dimension(s%nx+1,s%ny+1),intent(in) :: connected 00596 real*8,dimension(s%nx+1,s%ny+1),intent(out) :: fracdt,infil 00597 ! local 00598 integer :: i,j 00599 logical :: turbapprox 00600 real*8,dimension(s%nx+1,s%ny+1) :: Kzupd 00601 00602 ! initialise 00603 fracdt = 0.d0 00604 infil = 0.d0 00605 ! 00606 ! infiltration depends on turbulent or laminar method 00607 select case (par%gwscheme) 00608 case (GWSCHEME_LAMINAR) 00609 turbapprox = .false. 00610 case (GWSCHEME_TURBULENT) 00611 turbapprox = .true. 00612 end select 00613 ! 00614 ! 00615 ! Start Kzupd by seeding with Kz. 00616 Kzupd = Kzinf 00617 do j=1,s%ny+1 00618 do i=1,s%nx+1 00619 if (.not. connected(i,j)) then 00620 if (s%wetz(i,j)==1 .and. s%gwlevel(i,j)<s%zb(i,j)) then 00621 call gw_calc_local_infil(par,s%zb(i,j),s%hh(i,j),s%gwlevel(i,j),Kzinf(i,j),& 00622 s%dinfil(i,j),s%D50top(i,j),turbapprox, & 00623 fracdt(i,j),infil(i,j),Kzupd(i,j)) 00624 endif 00625 endif 00626 enddo 00627 enddo 00628 ! 00629 ! Update infiltration layer thickness 00630 where (infil>0.d0) 00631 s%dinfil = s%dinfil+par%dt*infil/par%por 00632 elsewhere 00633 ! s%dinfil = max(s%dinfil-par%dt*par%kz/par%por,0.d0) 00634 s%dinfil = 0.d0 00635 Kzupd = par%kz 00636 endwhere 00637 ! Ensure nothing went wrong here with fracdt 00638 fracdt = min(max(fracdt,0.d0),1.d0) 00639 ! Update Kz 00640 Kzinf = Kzupd 00641 end subroutine gw_unconnected_infil 00642 00643 subroutine gw_calculate_interfaceheight(s,gwhu,gwhv,initial) 00644 use xmpi_module 00645 use spaceparams 00646 00647 IMPLICIT NONE 00648 00649 type(spacepars),intent(in) :: s 00650 logical,intent(in) :: initial 00651 real*8,dimension(s%nx+1,s%ny+1),intent(out) :: gwhu,gwhv 00652 ! local 00653 integer :: i,j 00654 00655 ! HU 00656 if (initial) then 00657 do j=1,s%ny+1 00658 do i=1,s%nx 00659 if (s%gwhead(i+1,j)>s%gwhead(i,j)) then 00660 gwhu(i,j) = s%gwheight(i+1,j) 00661 elseif (s%gwhead(i+1,j)<s%gwhead(i,j)) then 00662 gwhu(i,j) = s%gwheight(i,j) 00663 else 00664 gwhu(i,j) = 0.5d0*(s%gwheight(i+1,j)+s%gwheight(i,j)) 00665 endif 00666 enddo 00667 enddo 00668 else 00669 do j=1,s%ny+1 00670 do i=1,s%nx 00671 if (s%gwu(i,j)>0.d0) then 00672 gwhu(i,j) = min(s%gwheight(i,j),max(s%zb(i+1,j)-s%gwbottom(i+1,j),0.d0)) 00673 elseif (s%gwu(i,j)<0.d0) then 00674 gwhu(i,j) = min(s%gwheight(i+1,j),max(s%zb(i,j)-s%gwbottom(i,j),0.d0)) 00675 else 00676 gwhu(i,j) = 0.5d0*(s%gwheight(i+1,j)+s%gwheight(i,j)) 00677 endif 00678 enddo 00679 enddo 00680 endif 00681 gwhu = max(gwhu,0.d0) ! in case of drying cells 00682 ! boundaries 00683 if (xmpi_isbot) then 00684 gwhu(s%nx+1,:) = gwhu(s%nx,:) 00685 endif 00686 00687 ! HV 00688 if (s%ny>0) then 00689 if (initial) then 00690 do j=1,s%ny 00691 do i=1,s%nx+1 00692 if (s%gwhead(i,j+1)>s%gwhead(i,j)) then 00693 gwhv(i,j) = s%gwheight(i,j+1) 00694 elseif (s%gwhead(i,j+1)<s%gwhead(i,j)) then 00695 gwhv(i,j) = s%gwheight(i,j) 00696 else 00697 gwhv(i,j) = 0.5d0*(s%gwheight(i,j+1)+s%gwheight(i,j)) 00698 endif 00699 enddo 00700 enddo 00701 else 00702 do j=1,s%ny 00703 do i=1,s%nx+1 00704 if (s%gwv(i,j)>0.d0) then 00705 gwhv(i,j) = min(s%gwheight(i,j),max(s%zb(i,j+1)-s%gwbottom(i,j+1),0.d0)) 00706 elseif (s%gwv(i,j)<0.d0) then 00707 gwhv(i,j) = min(s%gwheight(i,j+1),max(s%zb(i,j)-s%gwbottom(i,j),0.d0)) 00708 else 00709 gwhv(i,j) = 0.5d0*(s%gwheight(i,j+1)+s%gwheight(i,j)) 00710 endif 00711 enddo 00712 enddo 00713 endif 00714 gwhv = max(gwhv,0.d0) ! in case of drying cells 00715 ! Boundaries 00716 if (xmpi_isright) then 00717 gwhv(:,s%ny+1) = gwhv(:,s%ny) 00718 endif 00719 else ! ny==0 00720 gwhv(:,1) = s%gwheight(:,1) 00721 endif 00722 end subroutine gw_calculate_interfaceheight 00723 00724 pure function gw_calculate_smoothwetlayer(s,dwetlayer,px) result(r) 00725 use spaceparams 00726 00727 IMPLICIT NONE 00728 00729 type(spacepars),intent(in) :: s 00730 real*8,intent(in) :: dwetlayer,px 00731 real*8,dimension(s%nx+1,s%ny+1) :: r 00732 00733 ! Free surface head and ratio free surface to groundwater head to be used 00734 r = (s%zb-s%gwlevel)/dwetlayer 00735 ! This ratio should lie between 0 and 1 00736 r = min(max(r,0.d0),1.d0) 00737 ! Convert this to a smoother function at the edges 00738 r = 1.d0-(cos(r*px)+1)/2 00739 end function gw_calculate_smoothwetlayer 00740 00741 pure function gwCalculateHeadTop(nx,ny,zs,gwlevel,wetz,r,nonh,g,pres) result(gwhead) 00742 IMPLICIT NONE 00743 ! input 00744 integer,intent(in) :: nx,ny,nonh 00745 real*8,intent(in) :: g 00746 real*8,dimension(nx+1,ny+1),intent(in) :: zs,gwlevel,r,pres 00747 integer,dimension(nx+1,ny+1),intent(in) :: wetz 00748 ! result 00749 real*8,dimension(nx+1,ny+1) :: gwhead 00750 00751 ! If this point is wet (wetz==1), and 0<r<=1, additional head is added to 00752 ! the groundwater, described as ratio "r" times the difference in head between 00753 ! the surface water and the groundwater. 00754 if(nonh==1) then 00755 gwhead = gwlevel + wetz*(zs-gwlevel+pres/g)*(1.d0-r) 00756 else 00757 gwhead = gwlevel + wetz*(zs-gwlevel)*(1.d0-r) 00758 endif 00759 end function gwCalculateHeadTop 00760 00761 pure subroutine gwCalculateHeadGradient(nx,ny,gwhead,dsu,dnv,dheaddx,dheaddy) 00762 IMPLICIT NONE 00763 ! input/output 00764 integer,intent(in) :: nx,ny 00765 real*8,dimension(nx+1,ny+1),intent(in) :: gwhead,dsu,dnv 00766 real*8,dimension(nx+1,ny+1),intent(out) :: dheaddx,dheaddy 00767 ! internal 00768 integer :: i,j 00769 00770 dheaddx=0.d0 00771 dheaddy=0.d0 00772 00773 do j=1,ny+1 00774 do i=1,nx 00775 dheaddx(i,j)=(gwhead(i+1,j)-gwhead(i,j))/dsu(i,j) 00776 end do 00777 end do 00778 00779 do j=1,ny 00780 do i=1,nx+1 00781 dheaddy(i,j)=(gwhead(i,j+1)-gwhead(i,j))/dnv(i,j) 00782 end do 00783 end do 00784 end subroutine gwCalculateHeadGradient 00785 00786 subroutine gw_solver(par,s,hbc,Kx,Ky,Kz,hu,hv,fracdt) 00787 use params, only: parameters 00788 use xmpi_module 00789 use spaceparamsdef 00790 use solver_module, only: solver_tridiag,solver_sip 00791 use paramsconst 00792 00793 IMPLICIT NONE 00794 00795 type(parameters),intent(in) :: par 00796 type(spacepars) :: s 00797 real*8,dimension(s%nx+1,s%ny+1),intent(in) :: hbc 00798 real*8,dimension(s%nx+1,s%ny+1),intent(in) :: Kx,Ky,Kz 00799 real*8,dimension(s%nx+1,s%ny+1),intent(in) :: hu,hv 00800 real*8,dimension(s%nx+1,s%ny+1),intent(in) :: fracdt 00801 ! internal 00802 real*8,dimension(:,:,:),allocatable,save :: A,work 00803 real*8,dimension(:,:),allocatable,save :: rhs,x,res 00804 integer :: i,j,n,m,k,it 00805 integer :: imin,imax,jmin,jmax 00806 real*8 :: dxum,dxup,dxpc 00807 real*8 :: dyvm,dyvp 00808 real*8 :: dyum,dyup,dxvm,dxvp,dA 00809 real*8 :: hcmx,hcc,hcpx 00810 real*8 :: hcmy,hcpy 00811 real*8 :: twothird 00812 real*8 :: hum,hup,hvm,hvp 00813 00814 twothird = 2.d0/3 00815 00816 i=0 00817 k=0 00818 00819 ! use tridiagonal solver if ny<=2 00820 if (s%ny<3) then 00821 if (par%ny==0) then 00822 j=1 00823 else 00824 j=2 00825 endif 00826 n = s%nx-1 00827 ! allocate Matrix solver coefficients 00828 if(.not.allocated(A)) then 00829 allocate(A(5,n,1)) 00830 allocate(work(1,n,1)) 00831 work = 0.d0 00832 allocate(rhs(n,1)) 00833 allocate(x(n,1)) 00834 endif 00835 ! build Matrix solver coefficients 00836 select case (par%gwheadmodel) 00837 case (GWHEADMODEL_PARABOLIC) 00838 do k=1,n 00839 i = k+1 00840 if (s%zb(i,1)>s%gwbottom(i,1)+par%eps) then 00841 ! abbreviations 00842 dxum = s%dsu(i-1,j) 00843 dxup = s%dsu(i,j) 00844 dxpc = s%dsz(i,j) 00845 hcmx = s%gwheight(i-1,j) 00846 hcc = s%gwheight(i,j) 00847 hcpx = s%gwheight(i+1,j) 00848 hum = hu(i-1,j) 00849 hup = hu(i,j) 00850 if (k==-1) then 00851 ! A(2,k,1) = 0.d0 ! dummy 00852 ! A(1,k,1) = +Kx(i,j)*hup/dxup*twothird*hcc**2 +Kz(i-1,j)*2*dxpc*hcc*(1.d0-fracdt(i,j)) 00853 ! A(3,k,1) = -Kx(i,j)*hup/dxup*twothird*hcpx**2 00854 ! rhs(k,1) = - Kx(i,j)*hbc(i+1,j)*hup/dxup + Kx(i+1,j)*hbc(i,j)*hup/dxup 00855 elseif (k==-n) then 00856 ! A(2,k,1) = -Kx(i,j)*hum/dxum*twothird*hcmx**2 00857 ! A(1,k,1) = Kx(i,j)*hum/dxum*twothird*hcc**2 +Kz(i,j)*2*dxpc*hcc*(1.d0-fracdt(i,j)) 00858 ! A(3,k,1) = 0.d0 ! dummy 00859 ! rhs(k,1) = Kx(i,j)*hbc(i,j)*hum/dxum - Kx(i,j)*hbc(i-1,j)*hum/dxum 00860 else 00861 A(2,k,1) = -Kx(i-1,j)*hum/dxum*twothird*hcmx**2 00862 A(1,k,1) = Kx(i-1,j)*hum/dxum*twothird*hcc**2 +Kx(i,j)*hup/dxup*twothird*hcc**2 + & 00863 Kz(i,j)*2*dxpc*hcc*(1.d0-fracdt(i,j)) 00864 A(3,k,1) = -Kx(i,j)*hup/dxup*twothird*hcpx**2 00865 rhs(k,1) = Kx(i-1,j)*hum*(hbc(i ,j)-hbc(i-1,j))/dxum & 00866 - Kx(i ,j)*hup*(hbc(i+1,j)-hbc(i ,j))/dxup 00867 endif 00868 else 00869 A(:,k,1) = 0.d0 00870 rhs(k,1) = 0.d0 00871 endif 00872 enddo 00873 case (GWHEADMODEL_EXPONENTIAL) 00874 do k=1,n 00875 i = k+1 00876 ! abbreviations 00877 dxum = s%dsu(i-1,j) 00878 dxup = s%dsu(i,j) 00879 dxpc = s%dsz(i,j) 00880 hcmx = s%gwheight(i-1,j) 00881 hcc = s%gwheight(i,j) 00882 hcpx = s%gwheight(i+1,j) 00883 hum = hu(i-1,j) 00884 hup = hu(i,j) 00885 if (k==-1) then 00886 A(2,k,1) = 0.d0 ! dummy 00887 A(1,k,1) = +Kx(i+1,j)*hup/dxup*twothird*hcc**2 +Kz(i,j)*2*dxpc*hcc*(1.d0-fracdt(i,j)) 00888 A(3,k,1) = -Kx(i+1,j)*hup/dxup*twothird*hcpx**2 00889 rhs(k,1) = - Kx(i+1,j)*hbc(i+1,j)*hup/dxup + Kx(i+1,j)*hbc(i,j)*hup/dxup 00890 elseif (k==-n) then 00891 A(2,k,1) = -Kx(i,j)*hum/dxum*twothird*hcmx**2 00892 A(1,k,1) = Kx(i,j)*hum/dxum*twothird*hcc**2 +Kz(i,j)*2*dxpc*hcc*(1.d0-fracdt(i,j)) 00893 A(3,k,1) = 0.d0 ! dummy 00894 rhs(k,1) = Kx(i,j)*hbc(i,j)*hum/dxum - Kx(i,j)*hbc(i-1,j)*hum/dxum 00895 else 00896 A(2,k,1) = -Kx(i-1,j)*hum/dxum*(cosh(hcmx)-1/hcmx*sinh(hcmx)) 00897 A(1,k,1) = Kx(i-1,j)*hum/dxum*(cosh(hcc)-1/hcc*sinh(hcc)) + & 00898 Kx(i,j)*hup/dxup*(cosh(hcc)-1/hcc*sinh(hcc)) + & 00899 Kz(i,j)*dxpc*sinh(hcc)*(1.d0-fracdt(i,j)) 00900 A(3,k,1) = -Kx(i,j)*hup/dxup*(cosh(hcpx)-1/hcpx*sinh(hcpx)) 00901 00902 rhs(k,1) = Kx(i-1,j)*hbc(i,j)*hum/dxum - Kx(i-1,j)*hbc(i-1,j)*hum/dxum & 00903 - Kx(i,j)*hbc(i+1,j)*hup/dxup + Kx(i,j)*hbc(i,j)*hup/dxup 00904 endif 00905 enddo 00906 end select 00907 call solver_tridiag(A,rhs,x,work(1,:,1),n-1,0,fixshallow=.true.) 00908 ! return to global variable 00909 s%gwcurv(2:s%nx,j) = x(:,1) 00910 select case (par%gwheadmodel) 00911 case (GWHEADMODEL_PARABOLIC) 00912 s%gwhead(2:s%nx,j) = hbc(2:s%nx,j) - twothird*x(:,1)*s%gwheight(2:s%nx,j)**2 00913 case (GWHEADMODEL_EXPONENTIAL) 00914 s%gwhead(2:s%nx,j) = hbc(2:s%nx,j)+ & 00915 x(:,1)/s%gwheight(2:s%nx,j)*sinh(s%gwheight(2:s%nx,j)) & 00916 -x(:,1)*cosh(s%gwheight(2:s%nx,j)) 00917 end select 00918 s%gwhead(1,j) = s%gwhead(2,j) 00919 s%gwhead(s%nx+1,j) = s%gwhead(s%nx,j) 00920 ! spread left and right 00921 if (s%ny==2) then 00922 s%gwhead(:,1) = s%gwhead(:,2) 00923 s%gwhead(:,3) = s%gwhead(:,2) 00924 endif 00925 else 00926 if (par%gwfastsolve==1) then 00927 ! Use tridiagonal solver per row with explicit longshore velocities 00928 n = s%nx+1 00929 m = s%ny+1 00930 ! allocate Matrix solver coefficients 00931 if(.not.allocated(A)) then 00932 allocate(A(5,n,1)) 00933 allocate(work(1,n,1)) 00934 work = 0.d0 00935 allocate(rhs(n,1)) 00936 allocate(x(n,1)) 00937 endif 00938 do j=2,m-1 00939 ! build Matrix solver coefficients 00940 select case (par%gwheadmodel) 00941 case (GWHEADMODEL_PARABOLIC) 00942 do i=1,n 00943 imin = max(i-1,1) 00944 imax = min(i+1,s%nx+1) 00945 ! abbreviations 00946 dxum = s%dsu(imin,j) 00947 dxup = s%dsu(i,j) 00948 dxpc = s%dsz(i,j) 00949 dA = s%dsdnzi(i,j) 00950 dyum = s%dnu(imin,j) 00951 dyup = s%dnu(i,j) 00952 dyvm = s%dnv(i,j-1) 00953 dyvp = s%dnv(i,j) 00954 dxvm = s%dsv(i,j-1) 00955 dxvp = s%dsv(i,j) 00956 hcmx = s%gwheight(imin,j) 00957 hcc = s%gwheight(i,j) 00958 hcpx = s%gwheight(imax,j) 00959 hum = hu(imin,j) 00960 hup = hu(i,j) 00961 hvm = hv(i,j-1) 00962 hvp = hv(i,j) 00963 ! wwvv problem what is the value of k here 00964 ! wwvv to avoid warnings about uninitialized value for k 00965 ! wwvv I initialize k at the start of the program 00966 A(2,k,1) = -Kx(imin,j)*hum*dyum/dxum*twothird*hcmx**2 00967 A(1,k,1) = Kx(imin,j)*hum*dyum/dxum*twothird*hcc**2 + & 00968 Kx(i,j)*hup*dyup/dxup*twothird*hcc**2 + & 00969 Kz(i,j)*2*dA*hcc*(1.d0-fracdt(i,j)) 00970 A(3,k,1) = -Kx(i,j)*hup*dyup/dxup*twothird*hcpx**2 00971 rhs(k,1) = Kx(imin,j)*hum*dyum*(hbc(i ,j)-hbc(imin,j))/dxum & 00972 - Kx(i ,j)*hup*dyup*(hbc(imax,j)-hbc(i ,j))/dxup & 00973 + hvm*dxvm*s%gwv(i,j-1) - hvp*dxvp*s%gwv(i,j) 00974 00975 enddo 00976 case (GWHEADMODEL_EXPONENTIAL) 00977 ! wwvv problem detected by compiler: should this not be an i-loop? 00978 ! wwvv compiler suspects uninitialized value for i, I initialize i 00979 ! wwvv to 0 at the start of the subroutine 00980 do k=1,n 00981 imin = max(i-1,1) 00982 imax = min(i+1,s%nx+1) 00983 ! abbreviations 00984 dxum = s%dsu(imin,j) 00985 dxup = s%dsu(i,j) 00986 dxpc = s%dsz(i,j) 00987 dA = s%dsdnzi(i,j) 00988 dyum = s%dnu(imin,j) 00989 dyup = s%dnu(i,j) 00990 dyvm = s%dnv(i,j-1) 00991 dyvp = s%dnv(i,j) 00992 dxvm = s%dsv(i,j-1) 00993 dxvp = s%dsv(i,j) 00994 hcmx = s%gwheight(imin,j) 00995 hcc = s%gwheight(i,j) 00996 hcpx = s%gwheight(imax,j) 00997 hum = hu(imin,j) 00998 hup = hu(i,j) 00999 hvm = hv(i,j-1) 01000 hvp = hv(i,j) 01001 A(2,k,1) = -Kx(imin,j)*hum*dyum/dxum*(cosh(hcmx)-1/hcmx*sinh(hcmx)) 01002 A(1,k,1) = Kx(imin,j)*hum*dyum/dxum*(cosh(hcc)-1/hcc*sinh(hcc)) + & 01003 Kx(i,j)*hup*dyup/dxup*(cosh(hcc)-1/hcc*sinh(hcc)) + & 01004 Kz(i,j)*dA*sinh(hcc)*(1.d0-fracdt(i,j)) 01005 A(3,k,1) = -Kx(i,j)*hup*dyup/dxup*(cosh(hcpx)-1/hcpx*sinh(hcpx)) 01006 01007 rhs(k,1) = Kx(imin,j)*hbc(i,j)*hum*dyum/dxum - Kx(i,j)*hbc(i-1,j)*hum*dyum/dxum & 01008 - Kx(i,j)*hbc(imax,j)*hup*dyup/dxup + Kx(i,j)*hbc(i,j)*hup*dyup/dxup 01009 enddo 01010 end select 01011 call solver_tridiag(A,rhs,x,work(1,:,1),n-1,0,fixshallow=.true.) 01012 s%gwcurv(:,j) = x(:,1) 01013 select case (par%gwheadmodel) 01014 case (GWHEADMODEL_PARABOLIC) 01015 s%gwhead(2:s%nx,j) = hbc(2:s%nx,j) - twothird*x(:,1)*s%gwheight(2:s%nx,j)**2 01016 case (GWHEADMODEL_EXPONENTIAL) 01017 s%gwhead(2:s%nx,j) = hbc(2:s%nx,j)+ & 01018 x(:,1)/s%gwheight(2:s%nx,j)*sinh(s%gwheight(2:s%nx,j)) & 01019 -x(:,1)*cosh(s%gwheight(2:s%nx,j)) 01020 end select 01021 enddo 01022 ! spread left and right 01023 s%gwhead(:,1) = s%gwhead(:,2) 01024 s%gwhead(:,s%ny+1) = s%gwhead(:,s%ny) 01025 else 01026 n = s%nx+1 01027 m = s%ny+1 01028 ! allocate Matrix solver coefficients 01029 if(.not.allocated(A)) then 01030 allocate(A(5,n,m)) 01031 allocate(work(5,n,m)) 01032 work = 0.d0 01033 allocate(rhs(n,m)) 01034 allocate(x(n,m)) 01035 x = 0.d0 01036 allocate(res(n,m)) 01037 res = 0.d0 01038 endif 01039 ! build Matrix solver coefficients 01040 select case (par%gwheadmodel) 01041 case (GWHEADMODEL_PARABOLIC) 01042 do j=1,m 01043 do i=1,n 01044 imin = max(i-1,1) 01045 imax = min(i+1,s%nx+1) 01046 jmin = max(j-1,1) 01047 jmax = min(j+1,s%ny+1) 01048 ! abbreviations (need to include dx and dy for mass conservation 01049 ! on curvilinear grid 01050 dxum = s%dsu(imin,j) 01051 dxup = s%dsu(i,j) 01052 dxpc = s%dsz(i,j) 01053 dA = s%dsdnzi(i,j) 01054 dyum = s%dnu(imin,j) 01055 dyup = s%dnu(i,j) 01056 dyvm = s%dnv(i,jmin) 01057 dyvp = s%dnv(i,j) 01058 dxvm = s%dsv(i,jmin) 01059 dxvp = s%dsv(i,j) 01060 hcmx = s%gwheight(imin,j) 01061 hcpx = s%gwheight(imax,j) 01062 hcc = s%gwheight(i,j) 01063 hcmy = s%gwheight(i,jmin) 01064 hcpy = s%gwheight(i,jmax) 01065 hum = hu(imin,j) 01066 hup = hu(i,j) 01067 hvm = hv(i,jmin) 01068 hvp = hv(i,j) 01069 ! Matrix A 01070 ! main diagonal 01071 A(1,i,j) = Kx(imin,j)*hum*dyum/dxum*twothird*hcc**2+Kx(i,j)*hup*dyup/dxup*twothird*hcc**2 + & 01072 Ky(i,jmin)*hvm*dxvm/dyvm*twothird*hcc**2+Ky(i,j)*hvp*dxvp/dyvp*twothird*hcc**2 + & 01073 Kz(i,j)*2*dA*hcc*(1.d0-fracdt(i,j)) 01074 ! down x 01075 A(2,i,j) = -Kx(imin,j)*hum*dyum/dxum*twothird*hcmx**2 01076 ! up x 01077 A(3,i,j) = -Kx(i,j)*hup*dyup/dxup*twothird*hcpx**2 01078 ! down y 01079 A(4,i,j) = -Ky(i,jmin)*hvm*dxvm/dyvm*twothird*hcmy**2 01080 ! up y 01081 A(5,i,j) = -Ky(i,j)*hvp*dxvp/dyvp*twothird*hcpy**2 01082 ! 01083 ! RHS 01084 rhs(i,j) = Kx(imin,j)*dyum*hum*(hbc(i ,j)-hbc(imin,j))/dxum & 01085 - Kx(i ,j)*dyup*hup*(hbc(imax,j)-hbc(i ,j))/dxup & 01086 + Ky(i,jmin)*dxvm*hvm*(hbc(i,j )-hbc(i,jmin))/dyvm & 01087 - Ky(i,j )*dxvp*hvp*(hbc(i,jmax)-hbc(i,j ))/dyvp 01088 enddo 01089 enddo 01090 res = 0.d0 01091 call solver_sip(A,rhs,x,res,work,it,s%nx,s%ny) 01092 s%gwcurv(:,:) = x 01093 s%gwcurv(1,:) = s%gwcurv(2,:) 01094 s%gwcurv(s%nx+1,:) = s%gwcurv(s%nx,:) 01095 s%gwcurv(:,1) = s%gwcurv(:,2) 01096 s%gwcurv(:,s%ny+1) = s%gwcurv(:,s%ny) 01097 end select 01098 endif ! speedup 2D 01099 01100 select case (par%gwheadmodel) 01101 case (GWHEADMODEL_PARABOLIC) 01102 s%gwhead = hbc - twothird*s%gwcurv*s%gwheight**2 01103 case (GWHEADMODEL_EXPONENTIAL) 01104 s%gwhead = hbc + s%gwcurv/s%gwheight*sinh(s%gwheight) & 01105 - s%gwcurv*cosh(s%gwheight) 01106 end select 01107 endif 01108 end subroutine gw_solver 01109 01110 subroutine gw_horizontal_infil_exfil(s,par,infilhorgw,infilhorsw,Kx,dynpres) 01111 ! compute horizontal part of infiltration/exfiltration 01112 use params, only: parameters 01113 use xmpi_module 01114 use spaceparamsdef 01115 01116 type(parameters),intent(in) :: par 01117 type(spacepars) :: s 01118 real*8,dimension(s%nx+1,s%ny+1),intent(in) :: Kx,dynpres 01119 real*8,dimension(s%nx+1,s%ny+1),intent(out) :: infilhorgw,infilhorsw 01120 ! internal 01121 integer :: i,j 01122 real*8 :: dz,dx,dy,vel,hsurf,hgw,dhead 01123 real*8,parameter :: visc = 1.0d-6 01124 real*8 :: vcr,scaleareab,scaleareas 01125 real*8 :: dum1,dum2,dum3 01126 01127 infilhorgw = 0.d0 01128 infilhorsw = 0.d0 01129 vcr = par%gwReturb/par%D50(1)*par%por*visc 01130 ! 01131 ! compute horizontal flow velocity between bed and surface water VERTICAL interfaces 01132 ! 01133 ! loop over all u-interfaces 01134 do i=1,s%nx 01135 do j=1,s%ny+1 01136 dz = s%zb(i+1,j)-s%zb(i,j) 01137 if (dz>0.d0 .and. s%wetz(i,j)==1) then ! jump up 01138 hsurf = s%zs(i,j)+dynpres(i,j)/par%g 01139 hgw = s%gwhead(i+1,j) 01140 dx = s%dsz(i+1,j) 01141 dhead = hsurf-hgw ! positive gradient if hsurf>hgw 01142 ! negative velocitity if infiltration 01143 call gw_calculate_velocities_local(vel,dum1,dhead/dx,Kx(i+1,j),0.d0,par%gwscheme, & 01144 .false.,.false.,par%gwheadmodel,dum2,dum3,vcr) 01145 vel = -vel ! convert negative down velocity into positive if infiltration, 01146 ! negative if exfiltration 01147 ! horizontal infiltration occurs along small side section, so scale the horizontal 01148 ! infiltration area by the vertical area of the cell used in the mass balance equation 01149 ! and infiltration velocities 01150 ! 01151 ! Scale area for bed cell and surface water cell 01152 scaleareab = dz/s%dsz(i+1,j) 01153 scaleareas = dz/s%dsz(i,j) 01154 ! Limit flow to that available in space in ground and 01155 ! in surface water volume 01156 if (vel>0.d0) then ! infiltration 01157 vel = min(vel, & 01158 s%hh(i,j)*s%dsz(i,j)/par%dt/dz, & 01159 max(s%zb(i+1,j)-s%gwlevel(i+1,j),0.d0)*par%por*s%dsz(i+1,j)/par%dt/dz) 01160 else 01161 vel = max(vel, & 01162 -(s%gwlevel(i+1,j)-s%gwbottom(i+1,j))*s%dsz(i+1,j)*par%por/par%dt/dz) 01163 endif 01164 infilhorgw(i+1,j) = infilhorgw(i+1,j)+vel*scaleareab 01165 infilhorsw(i,j) = infilhorsw(i,j)+vel*scaleareas 01166 elseif (dz<0.d0 .and. s%wetz(i+1,j)==1) then ! jump down 01167 dz = -dz 01168 hsurf = s%zs(i+1,j)+dynpres(i+1,j)/par%g 01169 hgw = s%gwhead(i,j) 01170 dx = s%dsz(i,j) 01171 dhead = hsurf-hgw ! positive gradient if hsurf>hgw 01172 ! negative velocitity if infiltration 01173 call gw_calculate_velocities_local(vel,dum1,dhead/dx,Kx(i,j),0.d0,par%gwscheme, & 01174 .false.,.false.,par%gwheadmodel,dum2,dum3,vcr) 01175 vel = -vel ! convert negative down velocity into positive if infiltration, 01176 ! negative if exfiltration 01177 ! horizontal infiltration occurs along small side section, so scale the horizontal 01178 ! infiltration area by the vertical area of the cell used in the mass balance equation 01179 ! and infiltration velocities 01180 ! 01181 ! Scale area for bed cell and surface water cell 01182 scaleareab = dz/s%dsz(i,j) 01183 scaleareas = dz/s%dsz(i+1,j) 01184 ! Limit flow to that available in space in ground and 01185 ! in surface water volume 01186 if (vel>0.d0) then ! infiltration 01187 vel = min(vel, & 01188 s%hh(i+1,j)*s%dsz(i+1,j)/par%dt/dz, & 01189 max(s%zb(i,j)-s%gwlevel(i,j),0.d0)*par%por*s%dsz(i,j)/par%dt/dz) 01190 else 01191 vel = max(vel, & 01192 -(s%gwlevel(i,j)-s%gwbottom(i,j))*s%dsz(i,j)*par%por/par%dt/dz) 01193 endif 01194 infilhorgw(i,j) = infilhorgw(i,j)+vel*scaleareab 01195 infilhorsw(i+1,j) = infilhorsw(i+1,j)+vel*scaleareas 01196 else ! equal bed height 01197 ! nothing 01198 endif 01199 enddo 01200 enddo 01201 ! 01202 ! 01203 ! loop over all v-interfaces 01204 do i=1,s%nx+1 01205 do j=1,s%ny 01206 dz = s%zb(i,j+1)-s%zb(i,j) 01207 if (dz>0.d0 .and. s%wetz(i,j)==1) then ! jump up 01208 hsurf = s%zs(i,j)+dynpres(i,j)/par%g 01209 hgw = s%gwhead(i,j+1) 01210 dy = s%dnz(i,j+1) 01211 dhead = hsurf-hgw ! positive gradient if hsurf>hgw 01212 ! negative velocitity if infiltration 01213 call gw_calculate_velocities_local(vel,dum1,dhead/dy,Kx(i,j+1),0.d0,par%gwscheme, & 01214 .false.,.false.,par%gwheadmodel,dum2,dum3,vcr) 01215 vel = -vel ! convert negative down velocity into positive if infiltration, 01216 ! negative if exfiltration 01217 ! horizontal infiltration occurs along small side section, so scale the horizontal 01218 ! infiltration area by the vertical area of the cell used in the mass balance equation 01219 ! and infiltration velocities 01220 ! 01221 ! Scale area for bed cell and surface water cell 01222 scaleareab = dz/s%dnz(i,j+1) 01223 scaleareas = dz/s%dnz(i,j) 01224 ! Limit flow to that available in space in ground and 01225 ! in surface water volume 01226 if (vel>0.d0) then ! infiltration 01227 vel = min(vel, & 01228 s%hh(i,j)*s%dsz(i,j)/par%dt/dz, & 01229 max(s%zb(i,j+1)-s%gwlevel(i,j+1),0.d0)*par%por*s%dnz(i,j+1)/par%dt/dz) 01230 else 01231 vel = max(vel, & 01232 -(s%gwlevel(i,j+1)-s%gwbottom(i,j+1))*s%dnz(i,j+1)*par%por/par%dt/dz) 01233 endif 01234 infilhorgw(i,j+1) = infilhorgw(i,j+1)+vel*scaleareab 01235 infilhorsw(i,j) = infilhorsw(i,j)+vel*scaleareas 01236 elseif (dz<0.d0 .and. s%wetz(i,j+1)==1) then ! jump down 01237 dz = -dz 01238 hsurf = s%zs(i,j+1)+dynpres(i,j+1)/par%g 01239 hgw = s%gwhead(i,j) 01240 dy = s%dnz(i,j) 01241 dhead = hsurf-hgw ! positive gradient if hsurf>hgw 01242 ! negative velocitity if infiltration 01243 call gw_calculate_velocities_local(vel,dum1,dhead/dy,Kx(i,j),0.d0,par%gwscheme, & 01244 .false.,.false.,par%gwheadmodel,dum2,dum3,vcr) 01245 vel = -vel ! convert negative down velocity into positive if infiltration, 01246 ! negative if exfiltration 01247 ! horizontal infiltration occurs along small side section, so scale the horizontal 01248 ! infiltration area by the vertical area of the cell used in the mass balance equation 01249 ! and infiltration velocities 01250 ! 01251 ! Scale area for bed cell and surface water cell 01252 scaleareab = dz/s%dnz(i,j) 01253 scaleareas = dz/s%dnz(i,j+1) 01254 ! Limit flow to that available in space in ground and 01255 ! in surface water volume 01256 if (vel>0.d0) then ! infiltration 01257 vel = min(vel, & 01258 s%hh(i,j+1)*s%dnz(i,j+1)/par%dt/dz, & 01259 max(s%zb(i,j)-s%gwlevel(i,j),0.d0)*par%por*s%dnz(i,j)/par%dt/dz) 01260 else 01261 vel = max(vel, & 01262 -(s%gwlevel(i,j)-s%gwbottom(i,j))*s%dnz(i,j)*par%por/par%dt/dz) 01263 endif 01264 infilhorgw(i,j) = infilhorgw(i,j)+vel*scaleareab 01265 infilhorsw(i,j+1) = infilhorsw(i,j+1)+vel*scaleareas 01266 else ! equal bed height 01267 ! nothing 01268 endif 01269 enddo 01270 enddo 01271 01272 end subroutine gw_horizontal_infil_exfil 01273 01274 subroutine gw_calculate_velocities(s,par,fracdt,gwu,gwv,gww,Kx,Ky,Kz,Kxupd,Kyupd,Kzupd) 01275 use params, only: parameters 01276 use xmpi_module 01277 use spaceparamsdef 01278 use paramsconst 01279 01280 IMPLICIT NONE 01281 01282 type(parameters),intent(in) :: par 01283 type(spacepars) :: s 01284 real*8,dimension(s%nx+1,s%ny+1),intent(in) :: fracdt 01285 real*8,dimension(s%nx+1,s%ny+1),intent(in) :: Kx,Ky,Kz 01286 real*8,dimension(s%nx+1,s%ny+1),intent(out) :: gwu,gwv,gww 01287 real*8,dimension(s%nx+1,s%ny+1),intent(out) :: Kxupd,Kyupd,Kzupd 01288 ! internal 01289 real*8,dimension(s%nx+1,s%ny+1) :: dheaddx,dheaddy 01290 real*8 :: vcr ! for turbulent/MODFLOW approximation 01291 real*8,parameter :: visc = 1.0d-6 01292 integer :: i,j 01293 01294 ! Calculate the head gradient 01295 call gwCalculateHeadGradient(s%nx,s%ny,s%gwhead,s%dsu,s%dnv,dheaddx,dheaddy) 01296 if (xmpi_istop) then 01297 dheaddx(1,:) = dheaddx(2,:) 01298 endif 01299 if (xmpi_isleft .and. s%ny>0) then 01300 dheaddy(:,1) = dheaddy(:,2) 01301 endif 01302 ! initialise 01303 Kxupd = Kx 01304 Kyupd = Ky 01305 Kzupd = Kz 01306 vcr = par%gwReturb/par%D50(1)*par%por*visc 01307 ! Compute of all loops 01308 ! u-direction 01309 do j=1,s%ny+1 01310 do i=1,s%nx+1 01311 call gw_calculate_velocities_local(gwu(i,j),Kxupd(i,j),dheaddx(i,j),Kx(i,j),0.d0, & 01312 par%gwscheme,.false.,par%wavemodel==WAVEMODEL_NONH,par%gwheadmodel, & 01313 s%gwcurv(i,j),s%gwheight(i,j),vcr) 01314 enddo 01315 enddo 01316 ! v-direction 01317 do j=1,s%ny+1 01318 do i=1,s%nx+1 01319 call gw_calculate_velocities_local(gwv(i,j),Kyupd(i,j),dheaddy(i,j),Ky(i,j),0.d0, & 01320 par%gwscheme,.false.,par%wavemodel==WAVEMODEL_NONH,par%gwheadmodel, & 01321 s%gwcurv(i,j),s%gwheight(i,j),vcr) 01322 enddo 01323 enddo 01324 ! w-direction 01325 do j=1,s%ny+1 01326 do i=1,s%nx+1 01327 call gw_calculate_velocities_local(gww(i,j),Kzupd(i,j),0.d0,Kz(i,j),fracdt(i,j), & 01328 par%gwscheme,.true.,par%wavemodel==WAVEMODEL_NONH,par%gwheadmodel, & 01329 s%gwcurv(i,j),s%gwheight(i,j),vcr) 01330 enddo 01331 enddo 01332 end subroutine gw_calculate_velocities 01333 01334 pure subroutine gw_calculate_velocities_local(vel,Kupd,headgrad,Kin,fracdt,gwscheme,isvert,isnonh,headmodel,gwc,gwh,vcr) 01335 ! compute local groundwater velocity component 01336 use paramsconst 01337 IMPLICIT NONE 01338 01339 ! input/output 01340 real*8,intent(out) :: vel,Kupd 01341 real*8,intent(in) :: headgrad,Kin,fracdt 01342 integer, intent(in) :: gwscheme 01343 integer, intent(in) :: headmodel 01344 logical,intent(in) :: isvert,isnonh 01345 real*8,intent(in) :: gwc,gwh,vcr 01346 ! internal 01347 real*8 :: vest,err,fac,kest,vupd 01348 01349 select case (gwscheme) 01350 case (GWSCHEME_LAMINAR) 01351 if (isvert .and. isnonh) then ! vertical flow non-hydrostatic 01352 select case(headmodel) 01353 case (GWHEADMODEL_PARABOLIC) 01354 vel = -Kin*2*gwc*gwh*(1.d0-fracdt) 01355 case (GWHEADMODEL_EXPONENTIAL) 01356 vel = -Kin*gwc*sinh(gwh)*(1.d0-fracdt) 01357 end select 01358 elseif (isvert .and. .not. isnonh) then ! vertical flow hydrostatic 01359 vel = 0.d0 01360 else ! horizontal flow 01361 vel = -Kin*headgrad 01362 endif 01363 Kupd = Kin 01364 case (GWSCHEME_TURBULENT) 01365 if (isvert .and. isnonh) then ! vertical flow non-hydrostatic 01366 select case(headmodel) 01367 case (GWHEADMODEL_PARABOLIC) 01368 vest = -Kin*2*gwc*gwh 01369 if (abs(vest)>vcr) then 01370 err = 1.d0 01371 do while (err>0.001d0) 01372 fac = min(sqrt(vcr/max(abs(vest),vcr)),1.d0) 01373 kest = Kin*fac 01374 vupd = -kest*2*gwc*gwh 01375 vest = (vest+vupd)/2 01376 err = abs(vupd-vest)/abs(vest) 01377 enddo 01378 Kupd = kest 01379 else 01380 Kupd = Kin 01381 endif 01382 if (isnonh) then 01383 vel = -Kin*2*gwc*gwh ! result bound by pressure solver estimate, will 01384 ! update next time step with better K approximation 01385 else 01386 vel = -Kupd*2*gwc*gwh 01387 endif 01388 case (GWHEADMODEL_EXPONENTIAL) 01389 vest = -Kin*gwc*sinh(gwh) 01390 if (abs(vest)>vcr) then 01391 err = 1.d0 01392 do while (err>0.001d0) 01393 fac = min(sqrt(vcr/max(abs(vest),vcr)),1.d0) 01394 kest = Kin*fac 01395 vupd = -kest*gwc*sinh(gwh) 01396 vest = (vest+vupd)/2 01397 err = abs(vupd-vest)/abs(vest) 01398 enddo 01399 Kupd = kest 01400 else 01401 Kupd = Kin 01402 endif 01403 if (isnonh) then 01404 vel = -Kin*gwc*sinh(gwh) ! result bound by pressure solver estimate, will 01405 ! update next time step with better K approximation 01406 else 01407 vel = -Kupd*gwc*sinh(gwh) 01408 endif 01409 end select ! head model 01410 vel = vel*(1.d0-fracdt) 01411 elseif (isvert .and. .not. isnonh) then ! vertical flow hydrostatic 01412 vel = 0.d0 01413 Kupd = Kin 01414 else ! horizontal flow 01415 vest = -Kin*headgrad 01416 if (abs(vest)>vcr) then 01417 err = 1.d0 01418 do while (err>0.001d0) 01419 fac = min(sqrt(vcr/max(abs(vest),vcr)),1.d0) 01420 kest = Kin*fac 01421 vupd = -kest*headgrad 01422 vest = (vest+vupd)/2 01423 err = abs(vupd-vest)/abs(vest) 01424 enddo 01425 Kupd = kest 01426 else 01427 Kupd = Kin 01428 endif 01429 if (isnonh) then 01430 vel = -Kin*headgrad ! result bound by pressure solver estimate, will 01431 ! update next time step with better K approximation 01432 else 01433 vel = -Kupd*headgrad 01434 endif 01435 endif 01436 end select ! turbulence model 01437 end subroutine gw_calculate_velocities_local 01438 01439 function gw_calculate_hydrostatic_w(s,par,ratio) result(infil) 01440 use params, only: parameters 01441 use xmpi_module 01442 use spaceparamsdef 01443 use paramsconst 01444 01445 IMPLICIT NONE 01446 01447 type(parameters) :: par 01448 type(spacepars),target :: s 01449 ! wwvv the following line from s.ind : 01450 real*8,dimension(:,:), pointer :: infil 01451 real*8,dimension(s%nx+1,s%ny+1) :: ratio 01452 ! local 01453 integer :: i,j 01454 real*8 :: w1,w2,w3,dummy,dummy2 01455 logical :: turbapprox 01456 01457 01458 ! wwvv the following line is from s.inp : 01459 infil => s%infil 01460 ! Select turbulent approximation of groundwater flow 01461 if (par%gwscheme==GWSCHEME_TURBULENT) then 01462 turbapprox = .true. 01463 else 01464 turbapprox = .false. 01465 endif 01466 ! 01467 ! Velocity in connected cells is based on part instantaneous recovery 01468 ! of volume (w1) and part darcy driven flow due to top pressure (w2). 01469 ! These velocities are weighted according to 'ratio', the closeness 01470 ! of the groundwater surface to the bed. 01471 if (s%ny==0) then 01472 do i=2,s%nx 01473 if (s%gwlevel(i,1)>s%zb(i,1)) then 01474 infil(i,1) = par%por*(s%zb(i,1)-s%gwlevel(i,1))/par%dt 01475 ! infil(i,1) = max(infil(i,1),-par%kz) 01476 elseif (s%wetz(i,1)==1) then 01477 ! subroutine returns infiltration rate 01478 call gw_calc_local_infil(par,s%zb(i,1),s%hh(i,1),s%gwlevel(i,1),par%kz,s%dinfil(i,1), & 01479 s%D50top(i,1),turbapprox,dummy,w1,dummy2) 01480 w1 = min(w1,(1.d0+s%hh(i,1)/(par%dwetlayer/3))*par%kz) 01481 ! part is instant, part is through infiltration 01482 w2 = par%por*(s%zb(i,1)-s%gwlevel(i,1))/par%dt 01483 w2 = min(w2,(s%hh(i,1)-par%eps)/par%dt) 01484 w3 = ratio(i,1)*w1+(1.d0-ratio(i,1))*w2 01485 ! this should not exceed the available space for water 01486 infil(i,1) = min(w3,(s%zb(i,1)-s%gwlevel(i,1))*par%por/par%dt) 01487 else 01488 infil(i,1) = 0.d0 01489 endif 01490 enddo 01491 ! boundaries 01492 if (xmpi_istop) then 01493 infil(1,1) = infil(2,1) 01494 endif 01495 if (xmpi_isbot) then 01496 infil(s%nx+1,1) = infil(s%nx,1) 01497 endif 01498 else ! s%ny>0 01499 do j=2,s%ny 01500 do i=2,s%nx 01501 if (s%gwlevel(i,j)>s%zb(i,j)) then 01502 infil(i,j) = par%por*(s%zb(i,j)-s%gwlevel(i,j))/par%dt 01503 elseif (s%wetz(i,j)==1) then 01504 ! subroutine returns infiltration rate 01505 call gw_calc_local_infil(par,s%zb(i,j),s%hh(i,j),s%gwlevel(i,j),par%kz,s%dinfil(i,j), & 01506 s%D50top(i,j),turbapprox,dummy,w1,dummy2) 01507 w1 = min(w1,(1.d0+s%hh(i,j)/(par%dwetlayer/3))*par%kz) 01508 ! part is instant, part is through infiltration 01509 w2 = par%por*(s%zb(i,j)-s%gwlevel(i,j))/par%dt 01510 w2 = min(w2,(s%hh(i,j)-par%eps)/par%dt) 01511 w3 = ratio(i,j)*w1+(1.d0-ratio(i,j))*w2 01512 ! this should not exceed the available space for water 01513 infil(i,j) = min(w3,(s%zb(i,j)-s%gwlevel(i,j))*par%por/par%dt) 01514 else 01515 infil(i,j) = 0.d0 01516 endif 01517 enddo 01518 enddo 01519 if (xmpi_istop) then 01520 infil(1,:) = infil(2,:) 01521 endif 01522 if (xmpi_isbot) then 01523 infil(s%nx+1,:) = infil(s%nx,:) 01524 endif 01525 if (xmpi_isleft) then 01526 infil(:,1) = infil(:,2) 01527 endif 01528 if (xmpi_isright) then 01529 infil(:,s%ny+1) = infil(:,s%ny) 01530 endif 01531 endif ! s%ny>0 01532 end function gw_calculate_hydrostatic_w 01533 01534 01535 pure subroutine gw_calc_local_infil(par,zb,hh,gwlevel,kzlocal,dinfil,D50top,turb,fracdt,infil,kzupd) 01536 use params, only: parameters 01537 01538 IMPLICIT NONE 01539 01540 type(parameters),intent(in) :: par 01541 real*8,intent(in) :: zb,hh,gwlevel,dinfil,D50top,kzlocal 01542 logical,intent(in) :: turb 01543 real*8,intent(out) :: fracdt,infil,kzupd 01544 ! local 01545 real*8,parameter :: visc = 1.0d-6 01546 real*8 :: dis 01547 real*8 :: vest,vupd,Re,err,kze,newinfil 01548 real*8,parameter :: beta = 3.236067977499790d0 ! golden ratio 01549 real*8,parameter :: alfa = 2.236067977499790d0 ! golden ratio 01550 logical :: firstloop 01551 real*8 :: twodtpdi,fourdtph,dtpsq,twodtp,disq,dtp 01552 ! 01553 ! Determine infiltration velocity in single cell 01554 ! 01555 ! The routine only solves Laminar/Turbulent unsaturated flow, 01556 ! saturated flow handled later by Poisson solver. The fraction of 01557 ! time that unsaturated flow occurs is given by fracdt. 01558 ! 01559 ! Unsaturated flow: 01560 ! w(n+1) = kz * (1+dp/dz) = kz * (1 + (hh)/(dz(n)+w(n+1)*dt/por) ) 01561 ! w -> (-dzold + dt/por k + Sqrt[dzold^2 + 2 dt/por dzold k + 4 dt/por hold k + dt^2 k^2])/(2 dt/por) 01562 ! 01563 ! The routine for turbulent flow is the same as for Darcy flow, 01564 ! but iterate until correct value of vest found 01565 ! 01566 ! 01567 ! Coefficients for implicit solution 01568 dtp = par%dt/par%por 01569 twodtp = 2*dtp 01570 twodtpdi = twodtp*dinfil 01571 fourdtph = 4*dtp*hh 01572 dtpsq = dtp**2 01573 disq = dinfil**2 01574 ! Compute infiltration velocity assuming fully-unsaturated flow 01575 if(turb) then 01576 ! First estimate without turbulence 01577 vest = ( (-dinfil + dtp*par%kz + & 01578 sqrt(disq + & 01579 twodtpdi*par%kz + & 01580 fourdtph*par%kz + & 01581 dtpsq*par%kz**2& 01582 )& 01583 )& 01584 /twodtp & 01585 ) 01586 Re = abs(vest)*D50top/par%por/visc 01587 if (Re>par%gwReturb) then 01588 err = 1.d0 01589 ! itialize with previous (turbulent) Kzinf 01590 kze = kzlocal 01591 firstloop = .true. 01592 do while (err>0.01d0) 01593 vupd = ( (-dinfil + dtp*kze + & 01594 sqrt(disq + & 01595 twodtpdi*kze + & 01596 fourdtph*kze + & 01597 dtpsq*kze**2& 01598 )& 01599 )& 01600 /twodtp & 01601 ) 01602 if (firstloop) then 01603 err = 1.d0 01604 firstloop = .false. 01605 else 01606 err = abs(vest-vupd)/abs(vest) 01607 endif 01608 ! New estimate of the velocity, using golden ratio 01609 vest = (vest+alfa*vupd)/beta 01610 ! update estimate of Kz for next iteration 01611 Re = abs(vest)*D50top/par%por/visc 01612 kze = par%kz*sqrt(par%gwReturb/Re) 01613 enddo 01614 kzupd = kze 01615 else 01616 kzupd = par%kz 01617 endif 01618 else 01619 ! No need to iterate 01620 vest = ( (-dinfil + dtp*par%kz + & 01621 sqrt(disq + & 01622 twodtpdi*par%kz + & 01623 fourdtph*par%kz + & 01624 dtpsq*par%kz**2& 01625 )& 01626 )& 01627 /twodtp & 01628 ) 01629 kzupd = par%kz 01630 endif 01631 ! now compute depth of infiltration at this rate 01632 dis = vest*par%dt/par%por 01633 ! what part of timestep is unsaturated, assuming 01634 ! (incorrectly) that this is linear? 01635 fracdt = max(0.d0,min((zb-gwlevel)/dis,1.d0)) 01636 infil = vest*fracdt ! this is the average over the WHOLE TIMESTEP 01637 ! check to see that the amount of water available is larger than the amount 01638 ! infiltrating 01639 if (infil > (hh-par%eps)/par%dt) then 01640 newinfil = max((hh-par%eps)/par%dt,0.d0) 01641 fracdt = fracdt*newinfil/infil 01642 infil = newinfil 01643 endif 01644 01645 01646 01647 01648 01649 01650 !! Distance from bed to groundwater level 01651 !dis = max(zb-gwlevel,0.d0) 01652 !! how long does it take to fill this distance under free vertical flow? 01653 !dtunsat = (dis*par%por) / (kzlocal*(1+hh/dis)) 01654 !! what part of timestep is unsaturated? 01655 !fracdt = min(dtunsat,par%dt)/par%dt 01656 !subdt = fracdt*par%dt/par%por 01657 !! does this need any unsaturated flow? 01658 !if (subdt>0.d0) then 01659 ! ! estimate vertical velocity due to unsaturated flow 01660 ! vest = ( (-dinfil + subdt*kzlocal + & 01661 ! sqrt(dinfil**2 + & 01662 ! 2*subdt*dinfil*kzlocal + & 01663 ! 4*subdt*hh*kzlocal + & 01664 ! subdt**2*kzlocal**2& 01665 ! )& 01666 ! )& 01667 ! /(2*subdt) & 01668 ! ) 01669 !else 01670 ! vest = 0.d0 01671 !endif 01672 !! Only set error if using turbulent flow approximation AND 01673 !! the Reynolds number is above the critical Re number 01674 !if (turb) then 01675 ! ! Calculate Reynolds number 01676 ! Re = abs(vest)*D50top/par%por/visc 01677 ! if (Re>par%gwReturb) then 01678 ! err = 1.d0 01679 ! endif 01680 !else 01681 ! err=-1.d0 01682 !endif 01683 !! update estimate if needed 01684 !kze = kzlocal ! note that this variable MUST remain separate from Kz(i,j) 01685 ! ! which is used to update the Poisson part of the equation 01686 !do while (err>0.001d0) 01687 ! Re = abs(vest)*D50top/par%por/visc 01688 ! kze = kzlocal*sqrt(par%gwReturb/Re) 01689 ! ! how long does it take to fill distance with new kz 01690 ! dtunsat = (dis*par%por) / (kze*(1+hh/dis)) 01691 ! ! what part of timestep unsaturated and saturated? 01692 ! fracdt = min(dtunsat,par%dt)/par%dt 01693 ! subdt = fracdt*par%dt/par%por 01694 ! ! new vertical velocity estimate 01695 ! vupd = ( (-dinfil + subdt*kze + & 01696 ! sqrt(dinfil**2 + & 01697 ! 2*subdt*dinfil*kze + & 01698 ! 4*subdt*hh*kze + & 01699 ! subdt**2*kze**2& 01700 ! )& 01701 ! )& 01702 ! /(2*subdt) & 01703 ! ) 01704 ! err = abs(vest-vupd)/abs(vest) 01705 ! vest = (vest+vupd)/2 01706 !enddo ! err>0.001 01707 !infil = vest*fracdt ! this is the average over the WHOLE TIMESTEP 01708 !! check to see that the amount of water available is larger than the amount 01709 !! infiltrating 01710 !if (infil > (hh-par%eps)/par%dt) then 01711 ! newinfil = max((hh-par%eps)/par%dt,0.d0) 01712 ! fracdt = fracdt*newinfil/infil 01713 ! infil = newinfil 01714 !endif 01715 !kzupd = kze 01716 end subroutine gw_calc_local_infil 01717 01718 ! TODO: subroutine is not used. Remove this 01719 #if 0 01720 pure subroutine gw_calc_local_connected_infil(par,gwhead,gwlevel,zb,hh,D50top,turb,zs,infil) 01721 use params, only: parameters 01722 01723 IMPLICIT NONE 01724 01725 type(parameters),intent(in) :: par 01726 real*8,intent(in) :: gwhead,gwlevel,zb,hh,D50top,zs 01727 logical,intent(in) :: turb 01728 real*8,intent(out) :: infil 01729 ! local 01730 real*8,parameter :: visc = 1.0d-6 01731 real*8 :: headdif 01732 real*8 :: vest,vupd,Re,err,kze 01733 logical :: infiltrate, exfiltrate 01734 01735 ! Determine infiltration and exfiltration velocity in single cell in case of hydrostatic 01736 ! groundwater computation 01737 ! 01738 ! Since in connected cells hydrostatic mode gwhead == headtop, we use the difference between 01739 ! headtop and gwhead when the cell needs filling, and the difference between gwlevel and zb 01740 ! when the cell needs emptying 01741 ! 01742 ! Saturated flow: 01743 ! infil = kz * (dp/dz) = kz * headdif/dz = kx * headdif / (infil*dt/por) 01744 ! infil = sqrt(kz * headdif * por/dt) 01745 ! 01746 err = 0 01747 01748 if(gwlevel<zb) then 01749 infiltrate = .true. 01750 headdif = min(zs-gwhead,hh) 01751 else 01752 infiltrate = .false. 01753 if(gwlevel>zb) then 01754 exfiltrate = .true. 01755 headdif = gwlevel-zb 01756 else 01757 exfiltrate = .false. 01758 endif 01759 endif 01760 01761 if (infiltrate .or. exfiltrate) then 01762 ! wwvv problem detected by compiler: 01763 ! wwvv it is possible the err does not get initialized 01764 ! wwvv so I initialize err at the beginning at the subroutine to 0 01765 ! compute infiltration rate 01766 kze = par%kx 01767 vest = sqrt(kze*headdif*par%por/par%dt) 01768 if (turb) then 01769 ! Calculate Reynolds number 01770 Re = abs(vest)*D50top/par%por/visc 01771 if (Re>par%gwReturb) then 01772 err = 1.d0 01773 endif 01774 else 01775 err=-1.d0 01776 endif 01777 ! Compute turbulent flow velocity 01778 do while (err>0.001d0) 01779 Re = abs(vest)*D50top/par%por/visc 01780 kze = par%kz*sqrt(par%gwReturb/Re) 01781 ! new vertical velocity estimate 01782 vupd = sqrt(kze*headdif*par%por/par%dt) 01783 err = abs(vest-vupd)/abs(vest) 01784 vest = (vest+vupd)/2 01785 enddo ! err>0.001 01786 else 01787 vest = 0.d0 01788 endif 01789 01790 if (exfiltrate) then 01791 vest = min(vest,(gwlevel-zb)/par%dt*par%por) 01792 infil = -vest 01793 else 01794 infil = min(vest,(hh-par%eps)/par%dt) 01795 infil = min(infil,(zb-gwlevel)/par%dt*par%por) 01796 endif 01797 01798 end subroutine gw_calc_local_connected_infil 01799 #endif 01800 01801 pure function gwCalculateHeadBottom(gwcurv,gwheadtop,gwheight,nx,ny,model) result(gwheadb) 01802 use paramsconst 01803 01804 IMPLICIT NONE 01805 integer,intent(in) :: nx,ny 01806 real*8,dimension(nx+1,ny+1),intent(in) :: gwcurv,gwheadtop,gwheight 01807 integer ,intent(in) :: model 01808 real*8,dimension(nx+1,ny+1) :: gwheadb 01809 ! internal 01810 01811 select case (model) 01812 case (GWHEADMODEL_PARABOLIC) 01813 gwheadb = gwheadtop-gwcurv*gwheight**2 01814 case (GWHEADMODEL_EXPONENTIAL) 01815 gwheadb = gwcurv+gwheadtop-gwcurv*cosh(gwheight) 01816 end select 01817 end function gwCalculateHeadBottom 01818 01819 01820 end module