!> !> @file poisson_petsc.f90 !> !> @brief !> !> @copyright !> Copyright (©) 2021 EPFL (Ecole Polytechnique Fédérale de Lausanne) !> SPC (Swiss Plasma Center) !> !> SPClibs is free software: you can redistribute it and/or modify it under !> the terms of the GNU Lesser General Public License as published by the Free !> Software Foundation, either version 3 of the License, or (at your option) !> any later version. !> !> SPClibs is distributed in the hope that it will be useful, but WITHOUT ANY !> WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS !> FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. !> !> You should have received a copy of the GNU Lesser General Public License !> along with this program. If not, see . !> !> @author !> (in alphabetical order) !> @author Trach-Minh Tran !> PROGRAM main USE petsc_bsplines IMPLICIT NONE TYPE(petsc_mat) :: amat DOUBLE PRECISION, ALLOCATABLE :: rhs(:), sol(:), arow(:) INTEGER :: nx=5, ny=4, ntrials=10 INTEGER :: nitmax=10000, nits DOUBLE PRECISION :: rtol=1.e-9 INTEGER :: n, nnz, nnz_loc INTEGER :: i, j, irow, jcol INTEGER :: ierr, me, npes, istart, iend DOUBLE PRECISION :: t0 INTEGER :: ncols, cols(5) ! Max nnz by row .LE. 5 ! CHARACTER(len=128) :: matfile='mat.dat', rhsfile='rhs.dat' LOGICAL :: file_exist ! NAMELIST /newrun/ nx, ny, nitmax, rtol, matfile, rhsfile ! CALL mpi_init(ierr) CALL mpi_comm_rank(MPI_COMM_WORLD, me, ierr) CALL mpi_comm_size(MPI_COMM_WORLD, npes, ierr) ! IF(me.EQ.0) THEN READ(*, newrun) WRITE(*, newrun) WRITE(*,'(a,i6)') 'npes =', npes END IF CALL mpi_bcast(nx, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) CALL mpi_bcast(ny, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) CALL mpi_bcast(nitmax, 1, MPI_INTEGER, 0, MPI_COMM_WORLD, ierr) CALL mpi_bcast(rtol, 1, MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr) CALL mpi_bcast(matfile, 128, MPI_CHARACTER, 0, MPI_COMM_WORLD, ierr) CALL mpi_bcast(rhsfile, 128, MPI_CHARACTER, 0, MPI_COMM_WORLD, ierr) ! n = nx*ny ! Rank of the matrix ! ! Initialize matrix ! CALL init(n, 1, amat, comm=MPI_COMM_WORLD) istart = amat%istart iend = amat%iend !!$ WRITE(*,'(a,i3.3,a,3i6)') 'PE', me, ': istart, iend', istart, iend ! ! INQUIRE(file=TRIM(matfile), exist=file_exist) ! IF( file_exist ) THEN CALL mpi_barrier(MPI_COMM_WORLD,ierr) t0 = mpi_wtime() CALL load_mat(amat, matfile) CALL mpi_barrier(MPI_COMM_WORLD,ierr) IF(me.EQ.0) WRITE(*,'(a,1pe12.3)') 'Mat. loading time (s)', mpi_wtime()-t0 ELSE ! ! Construct the matrix ! CALL mpi_barrier(MPI_COMM_WORLD,ierr) t0 = mpi_wtime() ALLOCATE(arow(5)) ! Max nnz per row .LE. 5 DO j=1,ny DO i=1,nx irow = numb(i,j) IF( irow.GE.istart .AND. irow.LE.iend) THEN ncols = 1; cols(ncols) = irow; arow(ncols) = 4.0d0 IF(i.GT.1) THEN ncols = ncols+1 cols(ncols) = numb(i-1,j); arow(ncols) = -1.0d0 END IF IF(i.LT.nx) THEN ncols = ncols+1 cols(ncols) = numb(i+1,j); arow(ncols) = -1.0d0 END IF IF(j.GT.1) THEN ncols = ncols+1 cols(ncols) = numb(i,j-1); arow(ncols) = -1.0d0 END IF IF(j.LT.ny) THEN ncols = ncols+1 cols(ncols) = numb(i,j+1); arow(ncols) = -1.0d0 END IF CALL putrow(amat, irow, arow(1:ncols), cols(1:ncols)) END IF END DO END DO DEALLOCATE(arow) CALL mpi_barrier(MPI_COMM_WORLD,ierr) IF(me.EQ.0) WRITE(*,'(a,1pe12.3)') 'Mat. construction time (s)', mpi_wtime()-t0 ! ! Convert to PETSC mat ! CALL mpi_barrier(MPI_COMM_WORLD,ierr) t0=mpi_wtime() CALL to_mat(amat) CALL mpi_barrier(MPI_COMM_WORLD,ierr) IF(me.EQ.0) WRITE(*,'(a,1pe12.3)') 'Mat. conversion time (s)', mpi_wtime()-t0 ! CALL save_mat(amat, matfile) END IF ! ! Matrix size and partition could have changed after loading from file! ! n = amat%rank istart = amat%istart iend = amat%iend ! nnz_loc = get_count(amat) CALL mpi_reduce(nnz_loc, nnz, 1, MPI_INTEGER, mpi_sum, 0, MPI_COMM_WORLD, ierr) IF(npes.LE.4) THEN WRITE(*,'(a,i3.3,a,3i6)') 'PE', me, ': istart, iend (after), nloc, nnz_loc', & & istart, iend, iend-istart+1, nnz_loc END IF ! ! Construct or read RHS ! CALL mpi_barrier(MPI_COMM_WORLD,ierr) t0 = mpi_wtime() ALLOCATE(rhs(n)) INQUIRE(file=TRIM(rhsfile), exist=file_exist) IF( file_exist ) THEN OPEN(unit=99, file=TRIM(rhsfile), status='old', form='unformatted') READ(99) rhs(1:n) CLOSE(99) CALL mpi_barrier(MPI_COMM_WORLD,ierr) IF(me.EQ.0) THEN WRITE(*,'(a,1pe12.3)') 'RHS read time (s)', mpi_wtime()-t0 END IF ELSE rhs = 0.0d0 ALLOCATE(arow(n)) DO i=istart, iend arow = 0.0d0 CALL getrow(amat, i, arow) rhs(i) = SUM(arow) ! => the exact solution is 1 END DO arow = rhs CALL mpi_allreduce(arow, rhs, n, MPI_DOUBLE_PRECISION, MPI_SUM, MPI_COMM_WORLD, ierr) DEALLOCATE(arow) IF( me.EQ.0 ) THEN ! All processes have the gobla rhs OPEN(unit=99, file=TRIM(rhsfile), status='new', form='unformatted') WRITE(99) rhs(1:n) CLOSE(99) END IF CALL mpi_barrier(MPI_COMM_WORLD,ierr) IF(me.EQ.0) THEN WRITE(*,'(a,1pe12.3)') 'RHS construction time (s)', mpi_wtime()-t0 END IF END IF CLOSE(99) CALL mpi_barrier(MPI_COMM_WORLD,ierr) ! ! Back solve ! ALLOCATE(sol(n)) ! CALL mpi_barrier(MPI_COMM_WORLD,ierr) sol = 0.0d0 t0=mpi_wtime() CALL bsolve(amat, rhs, sol, rtol, nitmax, nits) CALL mpi_barrier(MPI_COMM_WORLD,ierr) IF(me.EQ.0) THEN WRITE(*,'(a,1pe12.3,i8,1pe12.3)') 'Error, nits, solve time(s)', & & MAXVAL(ABS(sol-1.0d0)), nits, mpi_wtime()-t0 END IF CALL mpi_barrier(MPI_COMM_WORLD,ierr) t0=mpi_wtime() DO i=1,ntrials sol = 0.0d0 CALL bsolve(amat, rhs, sol, rtol, nitmax, nits) END DO CALL mpi_barrier(MPI_COMM_WORLD,ierr) IF(me.EQ.0) THEN WRITE(*,'(a,1pe12.3,i8,1pe12.3)') 'Error, nits, solve time(s)', & & MAXVAL(ABS(sol-1.0d0)), nits, (mpi_wtime()-t0)/REAL(ntrials) END IF ! ! Clean up ! DEALLOCATE(rhs) DEALLOCATE(sol) CALL destroy(amat) CALL PetscFinalize(ierr) CALL mpi_finalize(ierr) CONTAINS INTEGER FUNCTION numb(i,j) ! ! One-dimensional numbering ! Number first x then y ! INTEGER, INTENT(in) :: i, j numb = (j-1)*nx + i END FUNCTION numb END PROGRAM main