XBeach
|
00001 !============================================================================== 00002 ! MODULE SOLVER 00003 !============================================================================== 00004 00005 ! DATE AUTHOR CHANGES 00006 ! 00007 ! october 2009 Pieter Bart Smit New module 00008 00009 module solver_module 00010 00011 implicit none 00012 save 00013 00014 ! If mpi is defined, the non-hydrostatic module is NOT included in the compilation 00015 ! to avoid unwanted side effects. 00016 00017 00018 !****************************************************************************** 00019 ! INTERFACE 00020 !****************************************************************************** 00021 00022 private 00023 00024 !----------------------------- PARAMETERS ----------------------------------- 00025 include 'nh_pars.inc' 00026 00027 !----------------------------- VARIABLES ----------------------------------- 00028 00029 !--- PRIVATE VARIABLES --- 00030 logical :: initialized = .false. 00031 00032 integer(kind=iKind) :: itmea = 0 ! mean number of iterations 00033 integer(kind=iKind) :: itmin = 0 ! minimum number of iterations 00034 integer(kind=iKind) :: itmax = 0 ! maximum number of iterations 00035 integer(kind=iKind) :: ittot = 0 ! total number of iterations 00036 integer(kind=iKind) :: itcal = 0 ! total number calls 00037 integer(kind=iKind) :: itnconv = 0 ! total number of matrix calls which didn't converge 00038 00039 real(kind=rKind) :: reps = 0.005_rKind 00040 real(kind=rKind) :: alpha = 0.94_rKind 00041 integer(kind=iKind) :: maxit = 30 00042 00043 00044 real(kind=rKind),dimension(:,:) ,allocatable :: residual ! Residual vector 00045 real(kind=rKind),dimension(:,:,:),allocatable :: work ! work matrix 00046 00047 !--- PUBLIC VARIABLES --- 00048 00049 ! NONE 00050 00051 !--- PUBLIC SUBROUTINES --- 00052 00053 public solver_init !Allocates resources 00054 public solver_free !Free's resources 00055 public solver_solvemat !Solve system 00056 public solver_tridiag 00057 public solver_sip 00058 00059 !--- PRIVATE SUBROUTINES 00060 00061 ! NONE 00062 00063 contains 00064 ! 00065 !****************************************************************************** 00066 ! SUBROUTINES/FUNCTIONS 00067 !****************************************************************************** 00068 00069 ! 00070 !============================================================================== 00071 subroutine solver_init(nx,ny,par) 00072 !============================================================================== 00073 ! 00074 00075 00076 ! DATE AUTHOR CHANGES 00077 ! 00078 ! october 2009 Pieter Bart Smit New module 00079 00080 !------------------------------------------------------------------------------- 00081 ! DECLARATIONS 00082 !------------------------------------------------------------------------------- 00083 ! 00084 !-------------------------- PURPOSE ---------------------------- 00085 ! 00086 ! Initializes Solver 00087 ! 00088 00089 !-------------------------- DEPENDENCIES ---------------------------- 00090 00091 use xmpi_module, only: Halt_Program 00092 use params, only: parameters 00093 use logging_module 00094 use paramsconst 00095 00096 !-------------------------- ARGUMENTS ---------------------------- 00097 ! 00098 type(parameters),intent(in) :: par 00099 integer, intent(in) :: nx !Number of x-meshes 00100 integer, intent(in) :: ny !Number of y-meshes 00101 ! 00102 !-------------------------- LOCAL VARIABLES ---------------------------- 00103 00104 ! - NONE - 00105 00106 !------------------------------------------------------------------------------- 00107 ! IMPLEMENTATION 00108 !------------------------------------------------------------------------------- 00109 reps = par%solver_acc 00110 alpha = par%solver_urelax 00111 maxit = par%solver_maxit 00112 00113 ! If sol. met. ok -> allocate resources 00114 if (par%solver == SOLVER_SIPP) then !Solver is SIP 00115 allocate( work(5,1:nx+1,1:ny+1)); work = 0.0_rKind 00116 allocate(residual( 1:nx+1,1:ny+1)); residual = 0.0_rKind 00117 elseif (par%solver == SOLVER_TRIDIAGG) then !Solver is TRI-DIAG, check if possible 00118 allocate( work(5,1:nx+1,1:ny+1)); work = 0.0_rKind 00119 endif 00120 00121 initialized = .true. 00122 end subroutine solver_init 00123 00124 00125 00126 00127 00128 ! 00129 !============================================================================== 00130 subroutine solver_free 00131 !============================================================================== 00132 ! 00133 if (allocated(residual)) deallocate(residual) 00134 if (allocated(work)) deallocate(work) 00135 00136 end subroutine solver_free 00137 00138 00139 00140 00141 00142 00143 ! 00144 !============================================================================== 00145 subroutine solver_solvemat( amat , rhs , x , nx, ny, par) 00146 !============================================================================== 00147 ! 00148 00149 ! DATE AUTHOR CHANGES 00150 ! 00151 ! october 2009 Pieter Bart Smit New module 00152 00153 !------------------------------------------------------------------------------- 00154 ! DECLARATIONS 00155 !------------------------------------------------------------------------------- 00156 ! 00157 !-------------------------- PURPOSE ---------------------------- 00158 ! 00159 ! solves matrix 00160 ! 00161 00162 !-------------------------- DEPENDENCIES ---------------------------- 00163 00164 use xmpi_module 00165 use params, only: parameters 00166 use paramsconst 00167 00168 !-------------------------- ARGUMENTS ---------------------------- 00169 ! 00170 integer, intent(in) :: nx !Number of x-meshes 00171 integer, intent(in) :: ny !Number of y-meshes 00172 00173 real(kind=rKind),dimension(5,nx+1,ny+1) :: amat !the coefficient matrix used in the linear system 00174 real(kind=rKind),dimension(nx+1,ny+1) :: rhs !the right-hand side vector of the system of equations 00175 real(kind=rKind),dimension(nx+1,ny+1) ,intent(inout) :: x !solution of the linear system 00176 type(parameters),intent(in) :: par 00177 ! 00178 !-------------------------- LOCAL VARIABLES ---------------------------- 00179 00180 integer(kind=iKind) :: it 00181 00182 !------------------------------------------------------------------------------- 00183 ! IMPLEMENTATION 00184 !------------------------------------------------------------------------------- 00185 00186 if (.not. initialized) call solver_init(nx,ny,par) 00187 00188 if (par%solver == SOLVER_SIPP) then 00189 ! 00190 itcal = itcal+1 !Number of times the solver procedure is called 00191 residual = 0. 00192 00193 call solver_sip ( amat , rhs , x , residual , work , it ,nx, ny) !,reps) 00194 00195 ittot = ittot+it !Total number of iterations 00196 itmin = min(it,itmin) !Minimum number of iterations 00197 itmax = max(it,itmax) !Maximum number of iterations 00198 itmea = ittot/itcal !Mean number of iterations 00199 if (it>=par%solver_maxit) then 00200 itnconv = itnconv+1 !Number of times the solver did not converge 00201 endif 00202 ! 00203 elseif (par%solver == SOLVER_TRIDIAGG) then 00204 ! 00205 #ifdef USEMPI 00206 call xmpi_shift_zs(rhs) 00207 do it=1,3 00208 call xmpi_shift_zs(amat(it,:,:)) 00209 enddo 00210 #endif 00211 call solver_tridiag(amat,rhs,x,work,nx,ny) 00212 #ifdef USEMPI 00213 call xmpi_shift_zs(x) 00214 #endif 00215 ! 00216 endif 00217 00218 end subroutine solver_solvemat 00219 00220 ! 00221 !============================================================================== 00222 subroutine solver_tridiag ( amat , rhs , x ,cmat ,nx ,ny,fixshallow ) 00223 !============================================================================== 00224 ! 00225 00226 ! DATE AUTHOR CHANGES 00227 ! 00228 ! october 2009 Pieter Bart Smit New module 00229 00230 !------------------------------------------------------------------------------- 00231 ! DECLARATIONS 00232 !------------------------------------------------------------------------------- 00233 ! 00234 !-------------------------- PURPOSE ---------------------------- 00235 ! 00236 ! Solves matrix use the thomas (or tri-diagonal) algorithm. The solver is only 00237 ! applicable in the 1-DH case but is substantially faster than the SIP method in 00238 ! this case 00239 ! 00240 ! Algorithm is not the most efficient possible as the matrix Amat is still stored 00241 ! with 5 diagonals and 3 y-points. (Amat(5,s%nx+1,s%ny+1) as opposed to (Amat(3,s%nx+1)) 00242 ! This is easier to incorporate in the more general code. 00243 ! 00244 ! NOTE: rhs and matrix are not changed. 00245 ! 00246 !-------------------------- DEPENDENCIES ---------------------------- 00247 ! 00248 ! - NONE - 00249 ! 00250 !-------------------------- ARGUMENTS ---------------------------- 00251 ! 00252 integer, intent(in) :: nx !Number of x-meshes 00253 integer, intent(in) :: ny !Number of y-meshes 00254 logical, intent(in),optional :: fixshallow 00255 00256 real(kind=rKind),dimension(5,nx+1,ny+1),intent(in) :: amat !the coefficient matrix used in the linear system 00257 real(kind=rKind),dimension(nx+1,ny+1) ,intent(in) :: rhs !the right-hand side vector of the system of equations 00258 real(kind=rKind),dimension(nx+1,ny+1) ,intent(inout) :: x !solution of the linear system 00259 real(kind=rKind),dimension(1:nx+1) ,intent(inout) :: cmat !work vector 00260 00261 ! 00262 !-------------------------- LOCAL VARIABLES ---------------------------- 00263 00264 integer(kind=iKind) :: i !Index variable 00265 integer(kind=iKind) :: jindex !Index variable for superfast1D 00266 real (kind=rKind) :: fac !Auxillary variable 00267 logical :: lfixshallow 00268 00269 !------------------------------------------------------------------------------- 00270 ! IMPLEMENTATION 00271 !------------------------------------------------------------------------------- 00272 00273 if (ny>0) then 00274 jindex = 2 00275 else 00276 jindex = 1 00277 endif 00278 00279 if (present(fixshallow)) then 00280 lfixshallow = fixshallow 00281 else 00282 lfixshallow = .false. 00283 endif 00284 00285 fac = amat(1,1,jindex) 00286 if (abs(fac)<tiny(0.d0) .and. lfixshallow) then 00287 fac = sign(tiny(0.d0),fac) 00288 endif 00289 x(1,jindex) = rhs(1,jindex)/fac 00290 00291 !forward elimination 00292 do i=2,nx+1 00293 cmat(i) = amat(3,i-1,jindex)/fac 00294 fac = amat(1,i,jindex)-amat(2,i,jindex)*cmat(i) 00295 if (abs(fac)<tiny(0.d0) .and. lfixshallow) then 00296 fac = sign(tiny(0.d0),fac) 00297 endif 00298 x(i,jindex) = (rhs(i,jindex)-amat(2,i,jindex)*x(i-1,jindex))/fac 00299 enddo 00300 00301 !Backward substitution 00302 do i=nx,1,-1 00303 x(i,jindex) = x(i,jindex)-cmat(i+1)*x(i+1,jindex) 00304 enddo 00305 end subroutine solver_tridiag 00306 00307 ! 00308 !============================================================================== 00309 subroutine solver_sip ( amat , rhs , x , res , cmat , it ,nx, ny) !, acc) 00310 !============================================================================== 00311 ! 00312 ! programmer Marcel Zijlema 00313 ! 00314 ! Version 1.0 Date 01-07-2002 HYDRO01: first release 00315 ! Version 1.1 Date 17-07-2009 Adapted for XBeach (Pieter Smit) 00316 ! 00317 ! ********************************************************************** 00318 ! 00319 ! DESCRIPTION 00320 ! 00321 ! Solves system of equations for the Poisson equation 00322 ! for one layer by means of Stone's SIP solver 00323 ! ********************************************************************** 00324 ! 00325 ! INPUT / OUTPUT ARGUMENTS 00326 ! 00327 00328 use xmpi_module 00329 implicit none 00330 00331 integer(kind=iKind) ,intent(out) :: it !iteration count 00332 ! real(kind=rKind) ,intent(out) :: acc !iteration count 00333 integer, intent(in) :: nx !Number of x-meshes 00334 integer, intent(in) :: ny !Number of y-meshes 00335 00336 real(kind=rKind),dimension(5,nx+1,ny+1),intent(in) :: amat !the coefficient matrix used in the linear system 00337 real(kind=rKind),dimension(nx+1,ny+1) ,intent(in) :: rhs !the right-hand side vector of the system of equations 00338 real(kind=rKind),dimension(nx+1,ny+1) ,intent(inout) :: x !solution of the linear system 00339 real(kind=rKind),dimension(5,1:nx+1,1:ny+1),intent(inout) :: cmat !the matrix containing an ILU factorization 00340 real(kind=rKind),dimension(1:nx+1,1:ny+1) ,intent(inout) :: res !the residual vector 00341 ! 00342 ! LOCAL VARIABLES 00343 ! 00344 logical :: iconv = .false. ! indicator for convergence 00345 integer(kind=iKind) :: i ! X-direction 00346 integer(kind=iKind) :: j ! Y-direction 00347 real(kind=rKind) :: bnorm ! 2-norm of right-hand side vector 00348 real(kind=rKind) :: epslin ! required accuracy in the linear solver 00349 real(kind=rKind) :: p1 ! auxiliary factor 00350 real(kind=rKind) :: p2 ! auxiliary factor 00351 real(kind=rKind) :: p3 ! auxiliary factor 00352 real(kind=rKind) :: rnorm ! 2-norm of residual vector 00353 real(kind=rKind) :: ueps ! minimal accuracy based on machine precision 00354 integer :: imin,imax,jmin,jmax 00355 00356 ! 00357 ! PARAMETERS 00358 ! 00359 00360 real(kind=rKind),parameter :: small=1.e-15_rKind ! a small number 00361 #ifdef USEMPI 00362 logical, parameter :: dompi = .true. ! use mpi or not use mpi 00363 #endif 00364 00365 ! ********************************************************************** 00366 ! 00367 ! I/O 00368 ! 00369 ! none 00370 ! ********************************************************************** 00371 ! 00372 ! SUBROUTINES CALLED 00373 ! 00374 ! 00375 ! ********************************************************************** 00376 ! 00377 ! ERROR MESSAGES 00378 ! 00379 ! none 00380 ! ********************************************************************** 00381 ! 00382 ! PSEUDO CODE 00383 ! 00384 ! The system of equations is solved using an incomplete 00385 ! factorization technique called Strongly Implicit Procedure 00386 ! (SIP) as described in 00387 ! 00388 ! H.L. Stone 00389 ! Iterative solution of implicit approximations of 00390 ! multidimensional partial differential equations 00391 ! SIAM J. of Numer. Anal., vol. 5, 530-558, 1968 00392 ! 00393 ! This method constructs an incomplete lower-upper factorization 00394 ! that has the same sparsity as the original matrix. Hereby, a 00395 ! parameter 0 <= alpha <= 1 is used, which should be around 0.92 00396 ! (when alpha > 0.95, the method may diverge). Furthermore, 00397 ! alpha = 0 means standard ILU decomposition. 00398 ! 00399 ! Afterward, the resulting system is solved in an iterative manner 00400 ! by forward and backward substitutions. 00401 ! ********************************************************************** 00402 ! 00403 00404 imin = 2 00405 imax = nx 00406 jmin = 2 00407 jmax = ny 00408 #ifdef USEMPI 00409 if (dompi) then 00410 imin = 3 00411 jmin = 3 00412 imax = nx-1 00413 jmax = ny-1 00414 00415 if (xmpi_istop) imin = 2 00416 if (xmpi_isbot) imax = nx 00417 if (xmpi_isleft) jmin = 2 00418 if (xmpi_isright) jmax = ny 00419 endif 00420 #endif 00421 00422 it = 0 00423 iconv = .false. 00424 00425 ! --- construct L and U matrices (stored in cmat) 00426 00427 bnorm = 0. 00428 do j = jmin,jmax 00429 do i = imin,imax 00430 p1 = alpha*cmat(5,i-1,j) 00431 p2 = alpha*cmat(3,i,j-1) 00432 cmat(2,i,j) = amat(2,i,j)/(1.+p1) 00433 cmat(4,i,j) = amat(4,i,j)/(1.+p2) 00434 p1 = p1*cmat(2,i,j) 00435 p2 = p2*cmat(4,i,j) 00436 p3 = amat(1,i,j) + p1 + p2 & 00437 - cmat(2,i,j)*cmat(3,i-1,j) & 00438 - cmat(4,i,j)*cmat(5,i,j-1) & 00439 + small 00440 cmat(1,i,j) = 1./p3 00441 cmat(3,i,j) = (amat(3,i,j)-p2)*cmat(1,i,j) 00442 cmat(5,i,j) = (amat(5,i,j)-p1)*cmat(1,i,j) 00443 bnorm = bnorm + rhs(i,j)*rhs(i,j) 00444 enddo 00445 enddo 00446 00447 00448 #ifdef USEMPI 00449 if(dompi) then 00450 call xmpi_allreduce(bnorm,mpi_sum) 00451 endif 00452 #endif 00453 00454 bnorm = sqrt(bnorm) 00455 00456 epslin = reps*bnorm 00457 ueps = 1000.*tiny(0.)*bnorm 00458 if ( epslin < ueps .and. bnorm > 0. ) then 00459 epslin = ueps 00460 end if 00461 00462 ! --- solve the system by forward and backward substitutions 00463 ! in an iterative manner 00464 00465 iconv = .false. 00466 00467 do while ( .not. iconv .and. it < maxit ) 00468 00469 it = it + 1 00470 rnorm = 0. 00471 00472 do j = jmin, jmax 00473 do i = imin, imax 00474 res(i,j) = rhs(i,j)-amat(1,i,j)*x(i,j) & 00475 -amat(2,i,j)*x(i-1,j) & 00476 -amat(3,i,j)*x(i+1,j) & 00477 -amat(4,i,j)*x(i,j-1) & 00478 -amat(5,i,j)*x(i,j+1) 00479 !Calculate norm 00480 rnorm = rnorm + res(i,j)*res(i,j) 00481 res(i,j) = (res(i,j) - cmat(2,i,j)*res(i-1,j) & 00482 - cmat(4,i,j)*res(i,j-1))* & 00483 cmat(1,i,j) 00484 enddo 00485 enddo 00486 00487 #ifdef USEMPI 00488 if (dompi) then 00489 call xmpi_allreduce(rnorm,mpi_sum) 00490 endif 00491 #endif 00492 00493 rnorm=sqrt(rnorm) 00494 00495 do j = ny, 2, -1 00496 do i = nx, 2, -1 00497 res(i,j) = res(i,j) - cmat(3,i,j)*res(i+1,j) - cmat(5,i,j)*res(i,j+1) 00498 x(i,j) = x(i,j) + res(i,j) 00499 enddo 00500 enddo 00501 00502 #ifdef USEMPI 00503 if (dompi) then 00504 call xmpi_shift_zs(x) 00505 endif 00506 #endif 00507 00508 iconv = rnorm .lt. epslin 00509 00510 enddo 00511 00512 end subroutine solver_sip 00513 00514 end module solver_module