现在的位置: 首页 > 综合 > 正文

SuperLU使用总结

2013年05月14日 ⁄ 综合 ⁄ 共 4020字 ⁄ 字号 评论关闭

第一次在CSDN上写博客,主要源于之前学习过程中在CSDN上下了很多资源,也看了很多技术大牛的贴,对我有很大的帮助,故在此也分享我学习的所得,希望对他人有些益处!

一、编译SuperLU

(注:第一部分“编译SuperLU”主要来自“竹间斋技术专区”http://hi.baidu.com/zhujianzhai/item/2606251ba96b850fe65c36eb,在此表示感谢!)

1、下载SuperLu文件

superLU的官网,下载最新版 http://crd.lbl.gov/~xiaoye/SuperLU/

然后解压到随便哪个文件夹里:**\SuperLU_4.0

2、生成库文件

(1)生成SuperLU.lib

1)新建一个工程A(这里命名为SuperLU),先将**\SuperLU_4.0\SRC 中的所有的.c文件添加到源文件文件夹中,所有的.h文件添加到头文件文件夹中
2)然后在工程右击->属性->配置属性->general->Configeration Type->选择static Liarary(.lib)这个,单击apply.(或者在建立工程的时候直接选创建的是静态库也可以)
3)将文件夹**\SuperLU_4.0\SRC 添加到右击->属性->C++->general->Additional Include Directories中

4)在DEBUG下调试编译

5)成功后生成Release版本。

这时候在新建的这个工程A的Release文件夹下就会生成**.lib,就是superLU用到的静态链接库

(2)生成BLAS.lib

由于SuperLu需要调用BLAS库中的一些函数,所以需要编译BLAS库,SuperLU官网上说BLAS库速度不快,可以使用推荐的Intel MKL、ATLAS, or Goto BLAS

这里仅以SuperLU下载之后文件中带的BLAS为例编译,即使之前有编译好的BLAS,也最好是用SuperLU文件夹中带的BLAS编译,减少出错的可能性。BLAS编译与SuperLU类似:

1)新建一个工程B(这里命名为BLAS, 记得也要将blas的相关xx.c和xx.h文件添加进工程中),然后在工程右击->属性->配置属性->general->ConfigerationType->选择static
Liarary(.lib)
这个,单击apply.(或者在建立工程的时候直接选创建的是静态库也可以)
2)
将文件夹**\SuperLU_4.0\BLAS 添加到右击->属性->C++->general->AdditionalInclude Directories中
3)
在DEBUG下调试编译
4)
成功后生成Release版本。

这里可能会出错,主要是slu_Cnames.h这个文件出错,里面包含的信息为.\SRC\slu_Cnames.h,说明这个文件就是SuperLU文件夹下SRC中的文件,如果建立BLAS工程的目录不在SRC的上层目录可能就会出错,我的做法是直接把这个文件移除,将SRC下的slu_Cnames.h文件添加到工程中来,这样编译就没错了。这是我编译中遇到的唯一问题,可能还会有其他问题,单总的注意事项就两个:①记得把工程编译类型设置为静态库。②将所需要的所有文件都放到工程中去。

二、使用SuperLU

SuperLU对于求解AX=B的方程时,A和B都是一维稀疏储存的,采用的是Harwell-Boeing格式,即列压缩储存格式。下面将从SuperLU传入数据格式和调用方法两个方面介绍。

1、SuperLU的Harwell-Boeing格式

以SuperLU的ug中的例子为例来说明

下面是一个5*5的矩阵,即行m=5,列n=5,非零元素个数为nnz

SuperLU采用三个一维数组记录该矩阵,a[nnz],asub[nnz],xa[n+1]。三个数组的含义如下:

a[]:记录所有非零的数据,记录顺序是以按列开始的,例如上面5*5的矩阵,在a中的顺序为19.0,0.63,0.63,21,0.57,0.57,21.00,-13.26,23.58,-0.24,21,-13.26,7.58,5.00,-0.77,21.00,34.20

asub[]:记录所有a中的元素在整个矩阵中的行编号(从0开始),

上面的5*5矩阵,asub的元素为:

0, 1 ,4,1,2,4,0,1,2,4,0,1,2,3,4,3,4

xa[]:记录一个矩阵中没列第一个非零元素在a中(注意是一维数组a,不是整体矩阵)的索引值(从0开始),但是这个数组的维数是n+1,最后一个元素貌似是非零元素的个数,我也没看懂为什么要这样。上面5*5的矩阵的xa元素为:

0,3,6,10,15,17

AX=B中B的格式我没仔细研究,因为SuperLU可以解矩阵方程,也就是说B也可以是一个矩阵,但是我主要是有限元方法,所以B是一个n*1的矩阵,直接用数组储存就可以了。

2、SuperLU的调用

(1)准备工作:

1)将**\SuperLU_4.0\SRC路径添加到C++\Additional Include Directories中;
2)再把路径**\工程A\Release(此路径下包含文件SuperLu.lib)和路径**工程B\Relese(此路径下包含文件BLAS.lib)添加到Linker->General->AdditionalLibrary Directories下;
3)将SuperLU.lib和BLAS.lib添加到Linker->Input->Additional Dependencies。

(2)调用方法

直接参考ug中的2.2 How to call a SuperLU routine。主要是做前期的准备工作,做好A和B的一维储存。其他步骤跟ug中实例的步骤一致:

1) 生成SuperLU的矩阵格式,传入参数是SuperMatrix格式的A;行列数m和n;一维储存的的三个数组 a、asub、xa;后面的三个参数是相应的格式控制,具体含义可参看ug

/* Create matrix A in the format expected by SuperLU. */
    dCreate_CompCol_Matrix(&A, m, n, nnz, a, asub, xa, SLU_NC, SLU_D, SLU_GE);

2)创建矩阵B,各参数含义同上

nrhs = 1;
    if ( !(rhs = doubleMalloc(m * nrhs)) ) ABORT("Malloc fails for rhs[].");
    for (i = 0; i < m; ++i) rhs[i] = 1.0;
    dCreate_Dense_Matrix(&B, m, nrhs, rhs, m, SLU_DN, SLU_D, SLU_GE);

3)做一些选项设置,主要是初始状态,求解器的一些选项设置,具体可参看ug,了解透彻对提高求解速度有帮助

/* Set the default input options. */
    set_default_options(&options);
    options.ColPerm = NATURAL;
最近发现我的有限元方法求解时将options.ColPerm设置为COLAMD速度可以提高好几倍(SuperLU默认的ColPerm值就是COLAMD),ColPer参数在ug中的描述是:Specifies how to permute the columns of the matrix for sparsity preservation.主要涉及A矩阵稀疏储存的变换方式,这个设置主要根据A来定,具体的选择涉及理论知识,小弟不才,实在不懂。

4)然后就是求解,各参数含义已经很明了,运行这个之后,数据B中保存求解的结果X

 dgssv(&options, &A, perm_c, perm_r, &L, &U, &B, &stat, &info);

5)结果输出,这个例子将A、U、L都输出了,唯独没有输出B,也就是结果,通过查找B的储存格式(SLU_DN),找到了输出B的函数:

dPrint_Dense_Matrix("B",&B); 

这个函数的具体定义为(在SRC\dutil.c中)

void  dPrint_Dense_Matrix(char *what, SuperMatrix*A)
{
    DNformat     *Astore= (DNformat *) A->Store;
    register int i, j, lda = Astore->lda;
    double       *dp;   
    printf("\nDense matrix %s:\n", what);
    printf("Stype %d, Dtype %d, Mtype %d\n", A->Stype,A->Dtype,A->Mtype);
    dp = (double *) Astore->nzval;
    printf("nrow %d, ncol %d, lda %d\n", A->nrow,A->ncol,lda);
    printf("\nnzval: ");
    for (j = 0; j < A->ncol; ++j) {
        for (i = 0; i < A->nrow; ++i) printf("%f  ",dp[i + j*lda]);
        printf("\n");
    }
    printf("\n");
    fflush(stdout);
}

可以看到这里的数据结构式将B存在一个数据块中,如果我们需要用的求解的结果,可以参考这个函数的代码来获得求解的结果。

这个实例的文件是SuperLU的example中的superlu.c,

建议编译好SuperLU.lib和BLAS.lib之后,将这个例子整个调通,可以在原先代码基础上加上

dPrint_Dense_Matrix("B",&B); 

输出计算结果,以检验是否正确。

总结:SuperLU求解速度比较快,并且还有并行版本,是做数值计算比较好的求解器。建议多看ug,更好的设置SuperLU可以提高计算速度。

本人水平有限,以上有错误和不足的地方,还请个人大牛指正!在此谢过!

抱歉!评论已关闭.