added separate modules for solver routines

This commit is contained in:
Bryan Herman 2012-01-27 20:28:28 -05:00
parent 5dde575415
commit dd209cd1c4
3 changed files with 704 additions and 0 deletions

278
src/cmfd_power_solver.F90 Normal file
View file

@ -0,0 +1,278 @@
module cmfd_power_solver
use cmfd_loss_operator, only: loss_operator,init_M_operator, &
& build_loss_matrix,print_M_operator,destroy_M_operator
use cmfd_prod_operator, only: prod_operator,init_F_operator, &
& build_prod_matrix,print_F_operator,destroy_F_operator
implicit none
private
public :: cmfd_power_execute
#include <finclude/petsc.h90>
type(loss_operator) :: loss
type(prod_operator) :: prod
Vec :: phi_n ! new flux eigenvector
Vec :: phi_o ! old flux eigenvector
Vec :: S_n ! new source vector
Vec :: S_o ! old source vector
KSP :: krylov ! krylov solver
PC :: prec ! preconditioner for krylov
integer :: ierr ! error flag
real(8) :: k_n ! new k-eigenvalue
real(8) :: k_o ! old k-eigenvalue
logical :: iconv ! did the problem converged
contains
!===============================================================================
! CMFD_POWER_EXECUTE
!===============================================================================
subroutine cmfd_power_execute()
! initialize solver
call init_solver()
! initialize matrices and vectors
call init_data()
! set up M loss matrix
call build_loss_matrix(loss)
! set up F production matrix
call build_prod_matrix(prod)
! set up krylov info
call KSPSetOperators(krylov, loss%M, loss%M, SAME_NONZERO_PATTERN, ierr)
call KSPSetUp(krylov,ierr)
! calculate preconditioner (ILU)
call PCFactorGetMatrix(prec,loss%M,ierr)
! begin power iteration
call execute_power_iter()
! extract results
call extract_results()
! deallocate petsc objects
call finalize()
end subroutine cmfd_power_execute
!===============================================================================
! INIT_DATA allocates matrices vectors for CMFD solution
!===============================================================================
subroutine init_data()
integer :: n ! problem size
real(8) :: guess ! initial guess
! set up matrices
call init_M_operator(loss)
call init_F_operator(prod)
! get problem size
n = loss%n
! set up flux vectors
call VecCreate(PETSC_COMM_WORLD,phi_n,ierr)
call VecSetSizes(phi_n,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(phi_n,ierr)
call VecCreate(PETSC_COMM_WORLD,phi_o,ierr)
call VecSetSizes(phi_o,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(phi_o,ierr)
! set up source vectors
call VecCreate(PETSC_COMM_WORLD,S_n,ierr)
call VecSetSizes(S_n,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(S_n,ierr)
call VecCreate(PETSC_COMM_WORLD,S_o,ierr)
call VecSetSizes(S_o,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(S_o,ierr)
! set initial guess
guess = 1.0_8
call VecSet(phi_n,guess,ierr)
call VecSet(phi_o,guess,ierr)
k_n = guess
k_o = guess
end subroutine init_data
!===============================================================================
! INIT_SOLVER
!===============================================================================
subroutine init_solver()
real(8) :: solvertol ! krylov tolerance
! set tolerance
solvertol = 1.0e-7_8
! set up krylov solver
call KSPCreate(PETSC_COMM_WORLD,krylov,ierr)
call KSPSetTolerances(krylov,solvertol,PETSC_DEFAULT_DOUBLE_PRECISION, &
& PETSC_DEFAULT_DOUBLE_PRECISION, &
& PETSC_DEFAULT_INTEGER,ierr)
call KSPSetType(krylov,KSPGMRES,ierr)
call KSPSetInitialGuessNonzero(krylov,PETSC_TRUE,ierr)
call KSPSetInitialGuessNonzero(krylov,PETSC_TRUE,ierr)
call KSPGetPC(krylov,prec,ierr)
call PCSetType(prec,PCILU,ierr)
call PCFactorSetLevels(prec,5,ierr)
call KSPSetFromOptions(krylov,ierr)
end subroutine init_solver
!===============================================================================
! EXECUTE_POWER_ITER in the main power iteration routine
! for the cmfd calculation
!===============================================================================
subroutine execute_power_iter()
real(8) :: num ! numerator for eigenvalue update
real(8) :: den ! denominator for eigenvalue update
real(8) :: one=1.0_8 ! one
integer :: i ! iteration counter
! reset convergence flag
iconv = .FALSE.
! begin power iteration
do i = 1,10000
! compute source vector
call MatMult(prod%F,phi_o,S_o,ierr)
! normalize source vector
call VecScale(S_o,one/k_o,ierr)
! compute new flux vector
call KSPSolve(krylov,S_o,phi_n,ierr)
! compute new source vector
call MatMult(prod%F,phi_n,S_n,ierr)
! compute new k-eigenvalue
call VecSum(S_n,num,ierr)
call VecSum(S_o,den,ierr)
k_n = num/den
! renormalize the old source
call VecScale(S_o,k_o,ierr)
! check convergence
call convergence()
! to break or not to break
if (iconv) exit
! record old values
call VecCopy(phi_n,phi_o,ierr)
k_o = k_n
end do
end subroutine execute_power_iter
!===============================================================================
! CONVERGENCE checks the convergence of eigenvalue, eigenvector and source
!===============================================================================
subroutine convergence()
real(8) :: ktol = 1.e-6_8 ! tolerance on keff
real(8) :: stol = 1.e-5_8 ! tolerance on source
real(8) :: kerr ! error in keff
real(8) :: serr ! error in source
real(8) :: one = -1.0_8 ! one
real(8) :: norm_n ! L2 norm of new source
real(8) :: norm_o ! L2 norm of old source
integer :: floc ! location of max error in flux
integer :: sloc ! location of max error in source
integer :: ierr ! petsc error code
integer :: n ! vector size
! reset convergence flag
iconv = .FALSE.
! calculate error in keff
kerr = abs(k_o - k_n)/k_n
! calculate max error in source
call VecNorm(S_n,NORM_2,norm_n,ierr)
call VecNorm(S_o,NORM_2,norm_o,ierr)
serr = abs(norm_n-norm_o)/norm_n
! check for convergence
if(kerr < ktol .and. serr < stol) iconv = .TRUE.
! print out to user (TODO: make formatted)
print *,k_n,kerr,serr
end subroutine convergence
!==============================================================================
! EXTRACT_RESULTS
!==============================================================================
subroutine extract_results()
use global, only: cmfd
PetscViewer :: viewer
PetscScalar, pointer :: phi_v(:) ! pointer to eigenvector info
integer :: n ! problem size
! get problem size
n = loss%n
! also allocate in cmfd object
if (.not. allocated(cmfd%phi)) allocate(cmfd%phi(n))
! convert petsc phi_object to cmfd_obj
call VecGetArrayF90(phi_n,phi_v,ierr)
cmfd%phi = phi_v
call VecRestoreArrayF90(phi_n,phi_v,ierr)
! save eigenvalue
cmfd%keff = k_n
! write out results
call PetscViewerBinaryOpen(PETSC_COMM_WORLD,'fluxvec.bin',FILE_MODE_WRITE, &
& viewer,ierr)
call VecView(phi_n,viewer,ierr)
call PetscViewerDestroy(viewer,ierr)
end subroutine extract_results
!==============================================================================
! FINALIZE
!==============================================================================
subroutine finalize()
! finalize data objects
call destroy_M_operator(loss)
call destroy_F_operator(prod)
call VecDestroy(phi_n,ierr)
call VecDestroy(phi_o,ierr)
call VecDestroy(S_n,ierr)
call VecDestroy(S_o,ierr)
! finalize solver objects
! call KSPDestroy(krylov,ierr)
end subroutine finalize
end module cmfd_power_solver

175
src/cmfd_slepc_solver.F90 Normal file
View file

@ -0,0 +1,175 @@
module cmfd_slepc_solver
use cmfd_loss_operator, only: loss_operator,init_M_operator, &
& build_loss_matrix,print_M_operator,destroy_M_operator
use cmfd_prod_operator, only: prod_operator,init_F_operator, &
& build_prod_matrix,print_F_operator,destroy_F_operator
implicit none
#include <finclude/petsc.h90>
#include <finclude/slepcsys.h>
#include <finclude/slepceps.h>
type(loss_operator) :: loss
type(prod_operator) :: prod
Vec :: phi ! eigenvector
EPS :: eps ! slepc eigenvalue object
ST :: st ! slepc spectral trans object
KSP :: ksp ! linear solver object
PC :: pc ! preconditioner object
integer :: ierr ! error flag
real(8) :: keff ! the converged eigenvalue
contains
!===============================================================================
! CMFD_SLEPC_EXECUTE
!===============================================================================
subroutine cmfd_slepc_execute()
! initialize data
call init_data()
! initialize solver
call init_solver()
! build operators
call build_loss_matrix(loss)
call build_prod_matrix(prod)
! set operators to EPS object
call EPSSetOperators(eps,prod%F,loss%M,ierr)
! solve the system
call EPSSolve(eps,ierr)
! extracts results to cmfd object
call extract_results()
! deallocate all slepc data
call finalize()
end subroutine cmfd_slepc_execute
!===============================================================================
! INIT_DATA allocates matrices vectors for CMFD solution
!===============================================================================
subroutine init_data()
integer :: n ! problem size
! set up matrices
call init_M_operator(loss)
call init_F_operator(prod)
! get problem size
n = loss%n
! set up eigenvector
call VecCreate(PETSC_COMM_SELF,phi,ierr)
call VecSetSizes(phi,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(phi,ierr)
end subroutine init_data
!===============================================================================
! INIT_SOLVER
!===============================================================================
subroutine init_solver()
character(LEN=20) :: epstype,sttype,ksptype,pctype
! create EPS Object
call EPSCreate(PETSC_COMM_WORLD,eps,ierr)
call EPSSetProblemType(eps,EPS_GNHEP,ierr)
call EPSSetType(eps,EPSPOWER,ierr)
call EPSSetFromOptions(eps,ierr)
call EPSSetWhichEigenpairs(eps,EPS_LARGEST_MAGNITUDE,ierr)
! get ST, KSP and PC objects
call EPSGetST(eps,st,ierr)
call STGetKSP(st,ksp,ierr)
call KSPGetPC(ksp,pc,ierr)
! set GMRES default
call KSPSetType(ksp,KSPGMRES,ierr)
! set precursor type
call PCSetType(pc,PCILU,ierr)
call PCFactorSetLevels(pc,4,ierr)
call PCSetFromOptions(pc,ierr)
! get all types and print
call EPSGetType(eps,epstype,ierr)
call STGetType(st,sttype,ierr)
call KSPGetType(ksp,ksptype,ierr)
call PCGetType(pc,pctype,ierr)
! display information to user
write(*,*) 'EPS TYPE IS: ',epstype
write(*,*) 'ST TYPE IS: ',sttype
write(*,*) 'KSP TYPE IS: ',ksptype
write(*,*) 'PC TYPE IS: ',pctype
end subroutine init_solver
!==============================================================================
! EXTRACT_RESULTS
!==============================================================================
subroutine extract_results()
use global, only: cmfd
integer :: n ! problem size
integer :: i_eig = 0 ! eigenvalue to extract
PetscViewer :: viewer ! petsc output object
PetscScalar, pointer :: phi_v(:) ! pointer to eigenvector info
! get problem size
n = loss%n
! also allocate in cmfd object
if (.not. allocated(cmfd%phi)) allocate(cmfd%phi(n))
! extract run information
call EPSGetEigenpair(eps,i_eig,keff,PETSC_NULL,phi,PETSC_NULL_OBJECT,ierr)
! convert petsc phi_object to cmfd_obj
call VecGetArrayF90(phi,phi_v,ierr)
cmfd%phi = phi_v
call VecRestoreArrayF90(phi,phi_v,ierr)
! save eigenvalue
cmfd%keff = keff
! write out results
call PetscViewerBinaryOpen(PETSC_COMM_WORLD,'fluxvec.bin',FILE_MODE_WRITE, &
& viewer,ierr)
call VecView(phi,viewer,ierr)
call PetscViewerDestroy(viewer,ierr)
end subroutine extract_results
!==============================================================================
! FINALIZE
!==============================================================================
subroutine finalize()
! finalize data objects
call destroy_M_operator(loss)
call destroy_F_operator(prod)
call VecDestroy(phi,ierr)
! finalize solver objects
call EPSDestroy(eps,ierr)
end subroutine finalize
end module cmfd_slepc_solver

251
src/cmfd_snes_solver.F90 Normal file
View file

@ -0,0 +1,251 @@
module cmfd_snes_solver
use cmfd_loss_operator, only: loss_operator,init_M_operator, &
& build_loss_matrix,print_M_operator,destroy_M_operator
use cmfd_prod_operator, only: prod_operator,init_F_operator, &
& build_prod_matrix,print_F_operator,destroy_F_operator
use cmfd_slepc_solver, only: cmfd_slepc_execute
implicit none
#include <finclude/petsc.h90>
type(loss_operator) :: loss
type(prod_operator) :: prod
Mat :: jac ! jacobian matrix
Vec :: resvec ! residual vector
Vec :: xvec ! results
KSP :: ksp ! linear solver context
PC :: pc ! preconditioner
SNES :: snes ! nonlinear solver context
integer :: ierr ! error flag
contains
!===============================================================================
! CMFD_SNES_EXECUTE
!===============================================================================
subroutine cmfd_snes_execute()
! call slepc solver
call cmfd_slepc_execute()
! initialize data
call init_data()
! initialize solver
call init_solver()
! solve the system
call SNESSolve(snes,PETSC_NULL,xvec,ierr)
! extracts results to cmfd object
call extract_results()
! deallocate all slepc data
call finalize()
end subroutine cmfd_snes_execute
!===============================================================================
! INIT_DATA allocates matrices vectors for CMFD solution
!===============================================================================
subroutine init_data()
use global, only: cmfd
integer :: k ! implied do counter
integer :: n ! problem size
real(8), pointer :: xptr(:) ! solution pointer
! set up matrices
call init_M_operator(loss)
call init_F_operator(prod)
! get problem size
n = loss%n
! create PETSc vectors
call VecCreate(PETSC_COMM_SELF,resvec,ierr)
call VecSetSizes(resvec,PETSC_DECIDE,n+1,ierr)
call VecSetFromOptions(resvec,ierr)
call VecCreate(PETSC_COMM_SELF,xvec,ierr)
call VecSetSizes(xvec,PETSC_DECIDE,n+1,ierr)
call VecSetFromOptions(xvec,ierr)
! set flux in guess
call VecSetValues(xvec,n,(/(k,k=0,n-1)/),cmfd%phi,INSERT_VALUES,ierr)
call VecAssemblyBegin(xvec,ierr)
call VecAssemblyEnd(xvec,ierr)
! set keff in guess
call VecGetArrayF90(xvec,xptr,ierr)
xptr(n+1) = 1.0_8/cmfd%keff
call VecRestoreArrayF90(xvec,xptr,ierr)
end subroutine init_data
!===============================================================================
! INIT_SOLVER
!===============================================================================
subroutine init_solver()
! create SNES context
call SNESCreate(PETSC_COMM_SELF,snes,ierr)
! set the residual function
call SNESSetFunction(snes,resvec,compute_nonlinear_residual,PETSC_NULL,ierr)
! set GMRES solver
call SNESGetKSP(snes,ksp,ierr)
call KSPSetType(ksp,KSPGMRES,ierr)
! set preconditioner
call KSPGetPC(ksp,pc,ierr)
call PCSetType(pc,PCNONE,ierr)
! set matrix free finite difference
call MatCreateSNESMF(snes,jac,ierr)
call SNESSetJacobian(snes,jac,jac,MatMFFDComputeJacobian,PETSC_NULL,ierr)
! set SNES options
call SNESSetFromOptions(snes,ierr)
end subroutine init_solver
!===============================================================================
! COMPUTE_NONLINEAR_RESIDUAL
!===============================================================================
subroutine compute_nonlinear_residual(snes,x,res,ierr)
! arguments
SNES :: snes ! nonlinear solver context
Vec :: x ! independent vector
Vec :: res ! residual vector
integer :: ierr ! error flag
Vec :: phi ! flux vector
Vec :: rphi ! flux part of residual
Vec :: phiM ! M part of residual flux calc
integer :: n ! problem size
real(8) :: lambda ! eigenvalue
real(8) :: reslamb ! residual for lambda
real(8), pointer :: xptr(:) ! pointer to solution vector
real(8), pointer :: rptr(:) ! pointer to residual vector
! get problem size
n = loss%n
! get pointers to vectors
call VecGetArrayF90(x,xptr,ierr)
call VecGetArrayF90(res,rptr,ierr)
! create petsc vector for flux
call VecCreate(PETSC_COMM_SELF,phi,ierr)
call VecSetSizes(phi,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(phi,ierr)
call VecCreate(PETSC_COMM_SELF,rphi,ierr)
call VecSetSizes(rphi,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(rphi,ierr)
! extract flux and place in petsc vector
call VecPlaceArray(phi,xptr,ierr)
call VecPlaceArray(rphi,rptr,ierr)
! extract eigenvalue
lambda = xptr(n+1)
! create operators
call build_loss_matrix(loss)
call build_prod_matrix(prod)
! create new petsc vectors to perform math
call VecCreate(PETSC_COMM_SELF,phiM,ierr)
call VecSetSizes(phiM,PETSC_DECIDE,n,ierr)
call VecSetFromOptions(phiM,ierr)
! calculate flux part of residual vector
call MatMult(loss%M,phi,phiM,ierr)
call MatMult(prod%F,phi,rphi,ierr)
call VecAYPX(rphi,-1.0_8*lambda,phiM,ierr)
! set eigenvalue part of residual vector
call VecDot(phi,phi,reslamb,ierr)
! map to ptr
rptr(n+1) = 0.5_8 - 0.5_8*reslamb
! reset arrays that are not used
call VecResetArray(phi,ierr)
call VecResetArray(rphi,ierr)
! restore arrays for residual and solution
call VecRestoreArrayF90(x,xptr,ierr)
call VecRestoreArrayF90(res,rptr,ierr)
! destroy all temp vectors
call VecDestroy(phi,ierr)
call VecDestroy(phiM,ierr)
call VecDestroy(rphi,ierr)
end subroutine compute_nonlinear_residual
!==============================================================================
! EXTRACT_RESULTS
!==============================================================================
subroutine extract_results()
use global, only: cmfd
integer :: n ! problem size
PetscViewer :: viewer
PetscScalar, pointer :: xptr(:) ! pointer to eigenvector info
! get problem size
n = loss%n
! also allocate in cmfd object
if (.not. allocated(cmfd%phi)) allocate(cmfd%phi(n))
! convert petsc phi_object to cmfd_obj
call VecGetArrayF90(xvec,xptr,ierr)
cmfd%phi = xptr(1:n)
! save eigenvalue
cmfd%keff = 1.0_8 / xptr(n+1)
call VecRestoreArrayF90(xvec,xptr,ierr)
! write out results
call PetscViewerBinaryOpen(PETSC_COMM_WORLD,'residual.bin',FILE_MODE_WRITE, &
viewer,ierr)
call VecView(resvec,viewer,ierr)
call PetscViewerDestroy(viewer,ierr)
end subroutine extract_results
!==============================================================================
! FINALIZE
!==============================================================================
subroutine finalize()
! finalize data objects
call destroy_M_operator(loss)
call destroy_F_operator(prod)
call VecDestroy(xvec,ierr)
call VecDestroy(resvec,ierr)
! finalize solver objects
call SNESDestroy(snes,ierr)
end subroutine finalize
end module cmfd_snes_solver