Call Paralution Solver from Fortran

Abstract: Paralution is an open source library for sparse iterative methods with special focus on multi-core and accelerator technology such as GPUs. It has a simple fortran interface and not well designed for multiple right-hand-sides. Here we defined a user friendly interface based on ISO_C_BINDING for Fortran FEA programmes to call Paralution solver.

keywords: Paralution, Fortran, sparse iterative method, iso_c_binding, FEA

  Paralution系由瑞典科研工作者开发的基于多种稀疏矩阵迭代求解方法的C++并行计算程序包。它支持包括OpenMP、GPU/CUDA、OpenCL、OpenMP/MIC等多种后台并行库,也允许通过MPI进行多节点并行加速计算。它是多许可证的开源软件,方便易用,且不依赖特定的硬件平台和软件库,支持主流的Linux、Windows和MacOS操作平台。具体内容可以参考其官方主页:www.paralution.com

  Paralution附带的算例中有Fortran调用的例子,只是对于有限元程序而言通常求解线性方程组AX=B的时候,右端项B不是向量形式而是矩阵形式。其次,在动力计算中总刚的稀疏结构通常而言并不发生改变,所以迭代求解器和预处理只需进行一次,这也是软件包附带算例没有考虑的。

  在有限元分析中调用Paralution计算线性稀疏方程组AX=B的一般步骤是:

1、初始化paralution环境;

2、设置求解器并导入总刚;

3、分析求解X;

4、退出并清空paralution环境

具体的介绍详见代码和算例

CPP code:

  1 #include <paralution.hpp>
  2 
  3 namespace fortran_module{
  4     // Fortran interface via iso_c_binding
  5     /*
  6     Author: T.Q
  7     Date: 2014.11
  8     Version: 1.1
  9     License: GPL v3
 10     */
 11     extern "C"
 12     {
 13         // Initialize paralution        
 14         void paralution_f_init();
 15         // Print info of paralution
 16         void paralution_f_info();
 17         // Build solver and preconditioner of paralution
 18         void paralution_f_build(const int[], const int[], const double[], int ,int);
 19         // Solve Ax=b
 20         void paralution_f_solve(const double[], double[], int , int&, double&, int&);
 21         // Stop paralution        
 22         void paralution_f_stop();
 23         // Subspace method for compute general eigenpairs 
 24         //void paralution_f_subspace();
 25     }
 26 
 27     int *row = NULL;// Row index
 28     int *col = NULL;// Column index    
 29     int *row_offset = NULL;// Row offset index for CSR
 30     double *val = NULL;// Value of sparse matrix
 31 
 32     double *in_x = NULL;// Internal x vector
 33     double *in_rhs = NULL;// Internal rhs vector
 34     
 35     bool var_clear = false;// Flag of variables clearance
 36     bool ls_build = false;// Flag of solver exist
 37     
 38     using namespace paralution;
 39     
 40 
 41     LocalMatrix<double> *mat_A = NULL;// Matrix A i.e. Stiffness matrix in FEM
 42     LocalMatrix<double> *mat_B = NULL;// Matrix B i.e. Mass matrix in FEM
 43 
 44     // Iterative Linear Solver and Preconditioner
 45     IterativeLinearSolver<LocalMatrix<double>, LocalVector<double>, double> *ls = NULL;
 46     Preconditioner<LocalMatrix<double>, LocalVector<double>, double> *pr = NULL;
 47 
 48     void paralution_f_clear()
 49     {
 50         // Clear variables
 51         
 52         if(ls!=NULL){ ls->Clear(); delete ls;}
 53         if(pr!=NULL){ pr->Clear(); delete pr;}
 54 
 55         if(row!=NULL)free_host(&row);
 56         if(col!=NULL)free_host(&col);
 57         if(row_offset!=NULL)free_host(&row_offset);
 58         if(val!=NULL)free_host(&val);
 59 
 60         if(in_x!=NULL)free_host(&in_x);
 61         if(in_rhs!=NULL)free_host(&in_rhs);
 62 
 63         if(mat_A!=NULL){ mat_A->Clear(); delete mat_A;}
 64         if(mat_B!=NULL){ mat_B->Clear(); delete mat_B;}
 65         
 66         var_clear = true;
 67         ls_build = false;
 68     }
 69 
 70     void paralution_f_init()
 71     {
 72         paralution_f_clear();        
 73         init_paralution();
 74     }
 75 
 76     void paralution_f_info()
 77     {
 78         info_paralution();
 79     }
 80 
 81     void paralution_f_stop()
 82     {
 83         paralution_f_clear();    
 84         stop_paralution();
 85     }
 86 
 87 
 88     void paralution_f_build(const int for_row[], const int for_col[],
 89         const double for_val[], int n, int nnz)
 90     {
 91         int i;
 92 
 93         if(var_clear==false)paralution_f_clear();
 94         
 95         // Allocate arrays
 96         allocate_host(nnz,&row);
 97         allocate_host(nnz,&col);
 98         allocate_host(nnz,&val);
 99         
100         // Copy sparse matrix data F2C
101         for(i=0;i<nnz;i++){
102             row[i] = for_row[i] - 1;// Fortran starts with 1 default
103             col[i] = for_col[i] - 1;
104             val[i] = for_val[i];}
105                 
106         // Load data
107         mat_A = new LocalMatrix<double>;        
108         mat_A->SetDataPtrCOO(&row,&col,&val,"Imported Fortran COO Matrix", nnz, n, n);        
109         mat_A->ConvertToCSR();// Manual suggest CSR format
110           mat_A->info();
111         
112         // Creat Solver and Preconditioner
113         ls = new CG<LocalMatrix<double>, LocalVector<double>, double>;
114         pr = new Jacobi<LocalMatrix<double>, LocalVector<double>, double>;
115 
116         ls->Clear();
117         ls->SetOperator(*mat_A);
118         ls->SetPreconditioner(*pr);
119         ls->Build();
120         
121         ls_build = true;
122 
123     }
124     
125     void paralution_f_solve(const double for_rhs[], double for_x[], int n,
126         int &iter, double &resnorm, int &err)
127     {
128         int i;
129         LocalVector<double> x;// Solution vector
130         LocalVector<double> rhs;// Right-hand-side vector
131         
132         assert(ls_build==true);
133 
134         if(in_rhs!=NULL)free_host(&in_rhs);
135         if(in_x!=NULL)free_host(&in_x);        
136         
137         allocate_host(n,&in_rhs);
138         allocate_host(n,&in_x);
139         // Copy and set rhs vector
140         for(i=0;i<n;i++){ in_rhs[i] = for_rhs[i];}
141         rhs.SetDataPtr(&in_rhs,"vector",n);
142         // Set solution to zero
143         x.Allocate("vector",n);
144         x.Zeros();
145         // Solve
146         ls->Solve(rhs,&x);
147         // Get solution
148         x.LeaveDataPtr(&in_x);
149         // Copy to array
150         for(i=0;i<n;i++){ for_x[i] = in_x[i];}
151         // Clear
152         x.Clear();
153         rhs.Clear();
154         // Get information
155         iter = ls->GetIterationCount();// iteration times
156         resnorm = ls->GetCurrentResidual();// residual
157           err = ls->GetSolverStatus();// error code
158     }
159     // TODO
160     // Subspace method for solve general eigenpairs for symmetric real positive
161     // defined matrix
162     // A*x=lambda*M*x
163     // A: matrix N*N i.e. stiffness matrix
164     // B: matrix N*N i.e. mass matrix
165     //
166     void paralution_f_subspace(const int for_row[], const int for_col[],
167         const int option[], const double for_stif[], const double for_mass[],
168         double eigval[], double eigvec[], int n, int nnz)
169     {
170     }    
171 }
View Code

Fortran code:

  1 module paralution
  2 use,intrinsic::iso_c_binding
  3 implicit none
  4 !*******************************************************************************
  5 !        Fortran module for call Paralution package
  6 !-------------------------------------------------------------------------------
  7 !            Author: T.Q.
  8 !            Date: 2014.11
  9 !           Version: 1.1
 10 !*******************************************************************************
 11 ! License: GPL v3        
 12 !------------------------------------------------------------------------------- 
 13 ! usage:
 14 !-------------------------------------------------------------------------------
 15 ! 1) call paralution_init
 16 ! 2) call paralution_info (optional)
 17 ! 3) call paralution_build 
 18 ! 4) call paralution_solve (support multi-rhs)
 19 ! 5) call paralution_stop
 20 !*******************************************************************************
 21 interface
 22     subroutine paralution_init()bind(c,name='paralution_f_init')
 23     end subroutine
 24     subroutine paralution_info()bind(c,name='paralution_f_info')
 25     end subroutine
 26     subroutine paralution_stop()bind(c,name='paralution_f_stop')
 27     end subroutine
 28     subroutine paralution_build(row,col,val,n,nnz)bind(c,name='paralution_f_build')
 29     import
 30     implicit none
 31     integer(c_int),intent(in),value::n,nnz
 32     integer(c_int),intent(in)::row(nnz),col(nnz)
 33     real(c_double),intent(in)::val(nnz)
 34     end subroutine
 35     subroutine paralution_solve_vec(rhs,x,n,iter,resnorm,err2)bind(c,name='paralution_f_solve')
 36     import
 37     implicit none
 38     integer(c_int),intent(in),value::n
 39     real(c_double),intent(in)::rhs(n)
 40     real(c_double)::x(n)
 41     integer(c_int)::iter,err2
 42     real(c_double)::resnorm
 43     end subroutine
 44 end interface
 45 contains
 46     subroutine paralution_solve(rhs,x,mat_rhs,mat_x,n,iter,resnorm,err2)
 47     implicit none
 48     integer(c_int)::n,iter,err2
 49     real(c_double),intent(in),optional::rhs(:),mat_rhs(:,:)
 50     real(c_double),optional::x(:),mat_x(:,:)
 51     real(c_double)::resnorm
 52 
 53     logical::isVec,isMat
 54     integer::i    
 55     isVec = present(rhs).and.present(x)
 56     isMat = present(mat_rhs).and.present(mat_x)
 57     
 58     if(isVec.and.(.not.isMat))then
 59         ! rhs and x both vector
 60         call paralution_solve_vec(rhs,x,n,iter,resnorm,err2)
 61     elseif(isMat)then
 62         ! rhs and x both matrix
 63         do i=1,size(mat_rhs,2)
 64             call paralution_solve_vec(mat_rhs(:,i),mat_x(:,i),n,iter,resnorm,err2)
 65         enddo
 66     else
 67         write(*,*)"Error too many input variables"
 68     endif
 69     return
 70     end subroutine
 71 end module
 72 
 73 program test
 74 use paralution
 75 implicit none
 76 real(kind=8)::a(10,10),b(10,2),x(10,2),val(28),res2
 77 integer::i,j,k,row(28),col(28),err2
 78 a = 0.D0
 79 a(1,[1,9]) = [1.7D0, .13D0]
 80 a(2,[2,5,10]) = [1.D0, .02D0, .01D0]
 81 a(3,3) = 1.5D0
 82 a(4,4) = 1.1D0
 83 a(5,5::1) = [2.6D0,0.D0,.16D0,.09D0,.52D0,.53D0]
 84 a(6,6) = 1.2D0
 85 a(7,[7,10]) = [1.3D0, .56D0]
 86 a(8,8:9) = [1.6D0, .11D0]
 87 a(9,9) = 1.4D0
 88 a(10,10) = 3.1D0
 89 
 90 write(*,*)"Data initialize"
 91 do i=1,size(a,1)
 92     do j=min(i+1,size(a,1)),size(a,1)
 93         a(j,i) = a(i,j)
 94     enddo
 95 enddo
 96 
 97 k=1
 98 do i=1,size(a,1)
 99     do j=1,size(a,2)
100         if(a(i,j)>1.D-4)then
101             row(k) = i
102             col(k) = j
103             val(k) = a(i,j)
104             write(*,*)i,j,val(k)
105             k = k + 1
106         endif
107     enddo
108 enddo
109 b(:,1) = [.287D0, .22D0, .45D0, .44D0, 2.486D0, .72D0, 1.55D0, 1.424D0, 1.621D0, 3.759D0]
110 b(:,2) = 1.5D0*b(:,1)
111 x = 0.D0
112 
113 i = 10
114 j = 28
115 k = 2
116 call paralution_init()
117 call paralution_info()
118 call paralution_build(row,col,val,i,j)
119 do k=1,2
120     call paralution_solve(rhs=b(:,k),x=x(:,k),n=i,iter=j,resnorm=res2,err2=err2)
121     write(*,*)"Iter times:",j," relative error:",res2," error code:",err2
122     write(*,*)x(:,k)
123 enddo
124 call paralution_solve(mat_rhs=b,mat_x=x,n=i,iter=j,resnorm=res2,err2=err2)
125 do k=1,2
126     write(*,*)"Iter times:",j," relative error:",res2," error code:",err2
127     write(*,*)x(:,k)
128 enddo
129 call paralution_stop()
130 end program
View Code

result:

 1  Data initialize
 2            1           1   1.7000000000000000     
 3            1           9  0.13000000000000000     
 4            2           2   1.0000000000000000     
 5            2           5   2.0000000000000000E-002
 6            2          10   1.0000000000000000E-002
 7            3           3   1.5000000000000000     
 8            4           4   1.1000000000000001     
 9            5           2   2.0000000000000000E-002
10            5           5   2.6000000000000001     
11            5           7  0.16000000000000000     
12            5           8   8.9999999999999997E-002
13            5           9  0.52000000000000002     
14            5          10  0.53000000000000003     
15            6           6   1.2000000000000000     
16            7           5  0.16000000000000000     
17            7           7   1.3000000000000000     
18            7          10  0.56000000000000005     
19            8           5   8.9999999999999997E-002
20            8           8   1.6000000000000001     
21            8           9  0.11000000000000000     
22            9           1  0.13000000000000000     
23            9           5  0.52000000000000002     
24            9           8  0.11000000000000000     
25            9           9   1.3999999999999999     
26           10           2   1.0000000000000000E-002
27           10           5  0.53000000000000003     
28           10           7  0.56000000000000005     
29           10          10   3.1000000000000001     
30 This version of PARALUTION is released under GPL.
31 By downloading this package you fully agree with the GPL license.
32 Number of CPU cores: 2
33 Host thread affinity policy - thread mapping on every core
34 PARALUTION ver B0.8.0
35 PARALUTION platform is initialized
36 Accelerator backend: None
37 OpenMP threads:2
38 LocalMatrix name=Imported Fortran COO Matrix; rows=10; cols=10; nnz=28; prec=64bit; asm=no; format=CSR; host backend={CPU(OpenMP)}; accelerator backend={None}; current=CPU(OpenMP)
39 PCG solver starts, with preconditioner:
40 Jacobi preconditioner
41 IterationControl criteria: abs tol=1e-15; rel tol=1e-06; div tol=1e+08; max iter=1000000
42 IterationControl initial residual = 5.33043
43 IterationControl RELATIVE criteria has been reached: res norm=6.83208e-07; rel val=1.28171e-07; iter=6
44 PCG ends
45  Iter times:           6  relative error:   6.8320832955793363E-007  error code:           2
46   0.10000029331886898       0.19999984686691041       0.30000008316594051       0.40000011088792048       0.49999997425190351       0.60000016633188091       0.70000002413346363       0.79999978910736969       0.90000002416832581        1.0000000083185150     
47 PCG solver starts, with preconditioner:
48 Jacobi preconditioner
49 IterationControl criteria: abs tol=1e-15; rel tol=1e-06; div tol=1e+08; max iter=1000000
50 IterationControl initial residual = 7.99564
51 IterationControl RELATIVE criteria has been reached: res norm=1.02481e-06; rel val=1.28171e-07; iter=6
52 PCG ends
53  Iter times:           6  relative error:   1.0248124943384603E-006  error code:           2
54   0.15000043997830351       0.29999977030036568       0.45000012474891066       0.60000016633188091       0.74999996137785507       0.90000024949782143        1.0500000362001956        1.1999996836610549        1.3500000362524884        1.5000000124777721     
55 PCG solver starts, with preconditioner:
56 Jacobi preconditioner
57 IterationControl criteria: abs tol=1e-15; rel tol=1e-06; div tol=1e+08; max iter=1000000
58 IterationControl initial residual = 5.33043
59 IterationControl RELATIVE criteria has been reached: res norm=6.83208e-07; rel val=1.28171e-07; iter=6
60 PCG ends
61 PCG solver starts, with preconditioner:
62 Jacobi preconditioner
63 IterationControl criteria: abs tol=1e-15; rel tol=1e-06; div tol=1e+08; max iter=1000000
64 IterationControl initial residual = 7.99564
65 IterationControl RELATIVE criteria has been reached: res norm=1.02481e-06; rel val=1.28171e-07; iter=6
66 PCG ends
67  Iter times:           6  relative error:   1.0248124943384603E-006  error code:           2
68   0.10000029331886898       0.19999984686691041       0.30000008316594051       0.40000011088792048       0.49999997425190351       0.60000016633188091       0.70000002413346363       0.79999978910736969       0.90000002416832581        1.0000000083185150     
69  Iter times:           6  relative error:   1.0248124943384603E-006  error code:           2
70   0.15000043997830351       0.29999977030036568       0.45000012474891066       0.60000016633188091       0.74999996137785507       0.90000024949782143        1.0500000362001956        1.1999996836610549        1.3500000362524884        1.5000000124777721   
View Code

 

posted @ 2014-11-28 15:59  pasuka  阅读(722)  评论(0编辑  收藏  举报