Who am I

我的照片
Hefei, Anhui, China
Research Fields: Satellite Geodesy

2014年5月5日星期一

fortran 关于二进制顺序读取

一: 关于二进制的读取
1)--------------------------------------------------------------------------------------
FOR的输出分 有格式form = 'formatted'、无格式form = 'unformatted'两种,前者是默认输出格式,即如果open语句里不声明form的话,那就是formatted。
无格式又分 直接存取access = 'direct'、间接存取access = 'seuqential' 两种,后者是无格式文件的默认格式。几个open示例:有格式文件:
open( 1, file = '...', status = 'new', form = 'formatted' )无格式/顺序文件:
open( 1, file = '...', status = 'new', form = 'unformatted', access = 'sequential' )无格式/直接文件: open( 1, file = '...', status = 'new', form = 'unformatted', access = 'direct', recl = ... )

2)--------------------------------------------------------------------------------------
如果是向 有格式文件 输出,则write语句写成:write( 1,* ) var; 或如write( 1,'(5i2)' ) var
如果是向 无格式/顺序文件 输出,则write语句应写成: write( 1 ) var
如果是向 无格式/直接文件 输出,则write语句应写成: write( 1, rec = k ) var

3)--------------------------------------------------------------------------------------
对于 无格式/直接文件 , open中的recl指明了一个输出记录的长度。它具体等于多少要看输出write语句如何写,同时write语句中的记录号rec也要写正确。
比如有一个m(20,30)的二维数组,可以有如下几种写法(注意recl, rec, m的变化):
a) 把整个数组看作一个记录(1个记录,1个记录长度20*30):
open ( 1, file = '...', status = 'new', form = 'unformatted', access = 'direct', recl = 20*30 )
write( 1, rec = 1 ) m
b) 把一行看作一个记录(20个记录,1个记录长度30):
open ( 1, file = '...', status = 'new', form = 'unformatted', access = 'direct', recl = 30 )
do k = 1, 20 
    write( 1, rec = k ) ( m( k, p ), p = 1, 30 )
end do
c) 把一个数组元素看作一个记录(20*30个记录,1个记录长度1):
open ( 1, file = '...', status = 'new', form = 'unformatted', access = 'direct', recl = 1 )
k = 0
do i = 1, 20 
   do j = 1, 30 
         k = k + 1 
         write( 1, rec = k ) m( i, j ) !rec表示输出数据的位置
或者 
         write( 1, rec = (i-1)*30+j ) m( i, j ) 
   end do
end do
注:二维数组是先存列再存行的,所以上述a)打印m元素的顺序与c)不同,而与下述d)相同
d) 把一个数组元素看作一个记录:
open ( 1, file = '...', status = 'new', form = 'unformatted', access = 'direct', recl = 1 )
k = 0
do j = 1, 30 
    do i = 1, 20 
           k = k + 1 
           write( 1, rec = k ) m( i, j )
或者  
           write( 1, rec = (j-1)*20+i ) m( i, j ) 
    end do
end do

在一些Fortran编译器中,对recl解释成字长而非字节,因此还需要将recl乘以4才能正确读取。后面将会详细讲解gfortran和ifort在这点上的区别。

4)--------------------------------------------------------------------------------------
二进制存放的数据还有一个反位的问题。一般在UNIX机上是二进制数是高位结束,在WIN和LINUX中是低位结束(没记错的话)。如果读数时出现很大的怪数,比如1.e+35之类,或者执行时显示读取文件到末尾,或者是记录不够长,并且你又确定程序没错,那么多半是反位问题的原因。这时如果你用的编译器有反位选项,可以加上,比如ifort编译器可以写:
ifort -convert big_endian xxx.f90   
ifort -convert little_endian xxx.f90
也可以直接在FOR程序的OPEN语句中说明,比如:
open( 1, file='...', form='unformatted', access='direct', recl=..., convert='big_endian' ) 
open( 1, file='...', form='unformatted', access='direct', recl=..., convert='little_endian') big_endian 适用于在本地PC读取UNIX服务器上生成的二进制数据。little_endian适用于在UNIX服务器读取本地PC生成的二进制数据。

二: 不同编译器的差别

1. 程序举例
program test
implicit none
real(kind=4) :: sst(144,73),q(144,73)
integer :: i,j,recl1
recl1=144*73*4
sst(:,:)=10.0
q(:,:)=20
open(11,file='out.grd',form='unformatted',access='direct',status='replace',recl=recl1)
write(11,rec=1) ((sst(i,j),i=1,144),j=1,73)
write(11,rec=2) ((q(i,j),i=1,144),j=1,73)
close(11)
end program

2. 分析
kind=4表示单精度数据占用4个字节,一般默认也是4个字节; recl的设置,不同的编译器是不同的:
1> 在pgi和gfortran编译器下, recl1=144*73*4,生成的二进制文件大小是84096字节(84096=144*73*4*2)。
2> 在ifort编译器下,recl1=144*73*1, 生成的二进制文件大小同上。
因此说明不同编译器在读取(写入)二进制文件时有*4或不*4的问题,pgi、gfortran需要,而ifort不需要。

如果是双精度数据时,在pgi和gfortran编译器下,recl=144*73*8,而ifort编译器下recl=144*73*2

如果用顺序(sequential)的方式读取二进制文件,文件开始和结束会自动加上文件标志符,而不同的编译器处理这点是有差别的,所以,当涉及到多个编译器时,建议用direct的方式读取二进制数据,因为可控性强。

另外,如果一次输出或读取的数据很大时,可能会超过recl(默认是kind=4)的数据区间,这时需要将数据分段输出或读取

三:参考资源
http://bbs.lasg.ac.cn/bbs/thread-13889-1-9.html
http://bbs.06climate.com/forum.php?mod=viewthread&tid=14763

2013年11月14日星期四

matlab 使用subplot时添加总title

使用subplot时,直接使用title命令时,只能将title添加在分图上,如果想给总图添加title应如何操作?

只需在最后一个subplot结束之后加上两行代码即可:
axes
set(gca,'visible','off','Title',text('string','\bfHello World!'))

2013年9月11日星期三

ubuntu12.04下安装matlab2013a

ubuntu12.04下安装matlab过程:

1. 下载matlab镜像文件(.iso),假设文件名为Matlab2013a.UNIX.iso
2. 挂载iso文件,命令为: sudo mount -o loop Matlab2013a.UNIX.iso /mnt
3. 进入挂载目录: cd /mnt
4. 安装: sudo ./install
5. 出现图形化安装界面,根据提示输入key以及license文件;
6. 默认安装位置为: /usr/local/MATLAB/R2013a
7. 更改权限: sudo chmod a+w -R ~/.matlab (重要)
8. 运行软件,命令为:sudo /usr/local/MATLAB/R2013a/bin/matlab (每次运行matalb程序输入命令太长,可以在.bashrc文件中加入alias matlab='bash /usr/local/MATLAB/R2013a/bin/matlab',这样以后只要输入matlab命令即可打开软件

注:由于license文件必须在ife的网络中才能有效,所以在以后的安装中注意这点,避免重复安装和卸载。


2013年5月30日星期四

自定义colormap meep (zt)

matlab 自定义colormap meep (from red through white to blue)

I have been thinking of using the colormap used in the MEEP software (an open source FDTD code) as a nice alternative to the classical Matlab colormap. Here is the short Matlab code to generate it and the resulting images:

mincolor    = [1 0 0]; % red
mediancolor = [1 1 1]; % white   
maxcolor    = [0 0 1]; % blue      

ColorMapSize = 4;
int1 = zeros(ColorMapSize,3); 
int2 = zeros(ColorMapSize,3);
for k=1:3
    int1(:,k) = linspace(mincolor(k), mediancolor(k), ColorMapSize);
    int2(:,k) = linspace(mediancolor(k), maxcolor(k), ColorMapSize);
end
meep = [int1(1:end-1,:); int2];

colormap(meep); 
colorbar

参考资料:
http://meyavuz.blogspot.de/2011/02/meep-colormap-for-matlab.html

2013年5月9日星期四

线性方程组求解与矩阵求逆

1. 线性方程组
在大地测量数据处理方面,线性方程组的求解无疑是最重要的问题之一。线性方程组的通用形式可写为\( AX=B \),系数矩阵A的维数为 \( (M,N) \),\( M \)为观测方程的个数(等于观测值的个数,1个观测值一个方程),\(N\)为需要求解的系数个数,因此向量\( X \) 的长度为\( N \),观测值向量\( B \)的长度为\( M \)。根据\(M\)和\( N \)的大小观测,可以将线性方程组分为三类:
  • \( M > N \), 超定方程组(也称矛盾方程组),此时通常求方程的LS解;
  • \( M = N \),适定方程组,有唯一解;
  • \( M < N \),欠定方程组,有无数组解,但通常求其最小范数解。
接下来主要讨论超定方程组和适定方程组的情况。
对于超定方程组,根据LS准则,可得到法方程:\( A^TAX=A^TB \),令\( C=A^TA,D=A^TB \),则\( C \)的维数为\((N,N)\),D的维数为\((N,1)\),此时法方程的求解与适定方程组一致。下面的讨论以适定方程组为例。

2. 线性方程组的求解与求逆的关系
线性方程组\( AX=B \)的求解在数学上表示为\( X=A^{-1} \times B \),但是在实际数值计算过程中,并不是一定要去计算\( A^{-1} \),如常用的消去法,三角分解前推回代法等。
矩阵求逆等价于求解方程组\( AX=I \),理论上与求解线性方程组一致。
在数值计算过程中,我们必须考虑计算的速度以及对内存的耗用情况,此时求逆和线性方程组的求解是两个不同的概念。
在求解线性方程组之前,必须明确你所需要的结果。如果只要最后结果\( X \),则尽量不要去求逆;
如果系数阵\( A \)的求逆无法避免,尽量选择快速的求逆算法。当然,对于小矩阵,就不用考虑两者的差别了。
用matlab函数表示以上情况:
\( X=A\B \) (基于LU分解,前推回代直接求解参数向量\( X \));
\( X=A^{-1} \cdot B \) (基于求逆求解参数向量\( X \) );
通常第一种方法速度快,占用内存少,但无法给出\( A^{-1} \)的信息。

3. 线性方程组的常用数值解法
通常把线性方程组的数值解法分为直接法和间接法。所谓直接法,就是经有限次运算即可求得方程组的精确解的方法;迭代法将求解的方程组转化为一个无限序列,其极限就是方程组的解。直接法一般来说用于求解系数矩阵阶数不是太高的问题,工作量较小,精度较高,但程序较复杂;迭代法主要用于一些高阶问题,一般程序较为简单,但工作量有时较大,耗用内存较多。
1> 直接法
 a. 克莱姆法则
\( x_i=\frac{det(A_i)}{detA} \)
算法复杂度:\( (n+1) \times [(n-1) \times n! + n!] \)
运算量非常大,理论上可行,实际计算中很少用;

三角形方程组的求解简单快速,所以通常将系数阵A转化为三角阵再进行运算。不同的分解形式对应不同的分解方法。求解下三角阵L的过程,称为前推\( (X_1-X_2---X_n) \);求解上三角阵U的过程,称为回代\( (X_n---X_2-X_1)\)。前推和回代的计算量一样,为\( \frac{n^2}{2} \)次乘法和加减法以及n次除法。

b. 高斯消去法
利用消去法,将方程组变换为上三角形方程组;整个消去过程需完成\( O(\frac{1}{3}n^3) \)次乘法和加法运算; 回代过程需\( \frac{n^2}{2} \)次乘法和加减法以及n次除法,故用消去法求解n阶方程组的计算量约为\( O(\frac{2}{3}n^3+2n^2) \);
从高斯消去法进一步完善,产生了列主元和全主元消去法,这两种方法在消去过程中的计算量进一步增加,但方法上更严谨。
每一步消去过程对应系数阵A左乘了一个初等变换矩阵,这一系列初等变换矩阵的乘积对应一个下三角矩阵L,故高斯消去法理论上等价与LU分解法。

c. LU分解法
将系数阵A直接分解成两个三角阵的乘积,根据矩阵运算的规则计算每个三角阵的元素。分解后\( AX=B \)的计算转化为两个三角形方程组的求解:
\( LY=B \) (前推,计算出Y)
\( UX=Y \) (回代,计算出X)
算法复杂度为 \( O(\frac{2}{3}n^3+2n^2) \),所以直接分解法与消去法的计算工作量基本上是相同的。

求解逆阵的算法复杂度为\( O(2n^3) \),是求解线性方程组的3倍。

d. 正交分解法
将矩阵A分解为一个正交阵和一个上三角阵的乘积,\( A=QR \)。根据分解方法,通常有Householder方法(镜像映射法)和Schmidt正交化方法。
运算复杂度为:\( O(\frac{4}{3}n^3+2n^2) \),与上面两种方法相比,运算量多一倍。
该方法在求解超定方程组时,较为优越,原因如下:
 \( A^TAX=A^TB \)  with \( A=QR \), then \( R^TQ^TQRX=R^TQ^TB \) and finally, \( RX=Q^TB \),因此,QR分解大大减少了计算量。

e. 对称正定矩阵的平方根法和\( LDL^T\)分解法
对称正定矩阵是特殊矩阵,可以用平方根法和\( LDL^T\)分解法(通常也叫做Cholesky decomposition),其运算量和存储量较普通消去法和LU分解法均节省一半,为\( O(\frac{1}{3}n^3+2n^2) \)
平方根分解:\( A=LL^T \)
\( LDL^T\)分解:\( L \) 为单位下三角阵

2> 迭代法
对于阶数不高的线性方程组,直接法有效,但对于阶数很高的矩阵,有时需要迭代法来解决。迭代的规则不同,迭代法也就不同。通常分为:线性迭代和非线性迭代;一阶迭代和P阶迭代;定常迭代和非定常迭代。具体,可参考教科书,如“数值计算方法(冯康)”。
共轭梯度法:非线性迭代法,适用于对称正定阵,不需选取任何迭代参数,使用方便。
此外,对于高阶方程组的处理通常还采用分块矩阵处理方法。节省内存需要量,但增加了计算量,需要更多的计算时间(由于内外存交换数据需要时间)。

4. 矩阵求逆
除了必须要求矩阵的逆,否则尽量不采用求逆阵的方法来求解线性方程组。
求逆阵的算法复杂度为\( O(2n^3) \),大约是同等方法求线性方程组\( O(\frac{2}{3}n^3) \)的3倍。
矩阵乘积的算法复杂度和矩阵求逆是等价的。
矩阵求逆当前最快方法的复杂度为\( O(n^{2.37}) \)
高斯消去法,LU分解法,SVD等,复杂度都为\( O(n^3) \),差别在于前面的系数。

特殊矩阵的处理通常会有特殊的方法,能大大减少运算量和存储量。

2013年5月7日星期二

lapack 线性方程组最小二乘求解函数dgels

1. DGELS函数简介
DGELS函数是利用最小二乘求解线性方程组(超定或欠定)AX=B或A'X=B的函数,处于driver level。利用LU分解或者QR分解进行求解。

2. DGELS函数调用格式
DGELS(TRANS, M, N, NRHS, A, LDA, B, LDB, WORK, LWORK, INFO)
输入参数:
TRANS(CHAR): 值为'N',表示No transpose, 对应AX=B; 值为'T',表示Transpose,对应A'X=B;
M,N(INT): 系数矩阵A的维数,M>N,超定(下面只以超定方程组为例),M<N,欠定;
NRHS(INT): 观测值向量B的列数(通常为1);
A(Double):系数阵;
LDA(INT):同DGESV函数中的LDA,LDA>=max(1,M),通常等于M;
B(Double):观测值向量,当TRANS=‘N’时,B(M,NRHS),当TRANS=‘T’时,B(N,NRHS);
LDB(INT):同DGESV函数中的LDB,LDB>=max(1,M),通常等于M;
LWORK(INT):Length of Work, 数组WORK的长度,见http://www.netlib.org/lapack/lug/node118.html
输出参数:
B(Double):B(1:N)为计算的结果;B(N+1:M)误差信息,具体见函数说明;
A(Double):M>N, QR分解矩阵信息;M<N, LU分解矩阵信息;
WORK(Double):维数为LWORK,存储空间(WORKspace)信息,具体见说明http://www.netlib.org/lapack/lug/node120.html
INFO:=0,成功执行;=-i,第i个参数illegal;=i,A的第i个对角元素为0,A非满秩阵,无LS解。

3. DGELS函数举例:

4. 同类型函数
  • DGELSY:利用完全正交分解计算AX=B的LS解
  • DGELSS:利用奇异值分解计算AX=B的LS解
  • DGELSD:利用奇异值分解(divide and conquer)计算AX=B的LS解
5. 参考资料

2013年5月6日星期一

lapack 线性方程组求解函数dgesv介绍

1. DGESV函数简介
DGESV函数是lapack函数库求解线性方程组AX=B的函数,处于drive level。利用LU分解进行求解,A=PLU,P为置换矩阵,L为单位下三角矩阵,U为上三角矩阵。

2. dgesv函数参数介绍
a) 形式
DGESV(N, NRHS, A, LDA, IPIV, B, LDB, INFO)
输入参数:
N(INT): 线性方程组的数目,矩阵A的维数;
NRHS(INT): 矩阵B的列数(一般为1,单列);
A(Double): 系数矩阵A,维数(LDA,N),通常LDA=N
LDA(INT):Leading Dimension of A, LDA>=max(1,N);
B(Double): 矩阵B,维数(LDB,NRHS),通常LDB=N,NRHS=1;
LDB(INT): Leading Dimension of B,LDB>=max(1,N);
输出结果:
A(Double):存储LU分解的L和U矩阵,L为单位下三角阵且对角线的单位值1没有存储;
IPIV(INT):维数为N,利用该矩阵的值可以推求置换矩阵P,starting from a unit matrix E, E矩阵的第i行与E矩阵的第IPIV(i)行进行交换
如IPIV=[2 2 3 4],则P矩阵的结果为:
B(Double):存储最终的求解结果X值;
INFO(INT):求解状态参数。INFO=0,成功执行;INFO<0,则INFO=-i,第i个参数是illegal value;INFO>0, U(i,i)=0, LU分解成功执行,但是U是奇异的,最终结果无法计算;

DGESV函数调用了Lapack Computation level的两个函数DGETRFDGETRS,前者是进行LU分解的函数,后者是利用分解的结果进行前向和后向推求最终结果X。简单介绍下这两个函数的调用格式:
DGETRF(M,N,A,LDA,IPIV,INFO),矩阵A的维度为(M,N),其它参数同上,返回结果为A(PLU),IPIV以及INFO。
DGETRS(TRANS,N,NRHS,A,LDA,IPIV,B,LDB,INFO),求解AX=B或A'X=B,该函数只有在INFO=0时才可以进行。输入变量'TRANS'为字符型,其意义如下:'N'对应AX=B; ‘T’对应A'X=B; 'C' 对应A'X=B (conjugate transpose),其它变量的意义同DGESV函数。

3. dgesv函数举例
http://www.nag.co.uk/lapack-ex/node5.html
最终返回结果:
B=X= [ 1.0000 -1.0000 3.0000 -5.0000];
A=PLU=[
5.2500 -2.9500 -0.9500 -3.8000
0.3429 3.8914 2.3757 0.4129
0.3010 -0.4631 -1.5139 0.2948
-0.2114 -0.3299 0.0047 0.1314]
IPIV=[2 2 3 4]; 从一个单位阵开始,单位阵的第行和第2行交换,第行和第2行交换,行和第3行交换,第行和第4行交换,
所以:
P=[0 1 0 0; 1 0 0 0; 0 0 1 0; 0 0 0 1];
L=[1 0 0 0; 0.3429 1 0 0; 0.3010 -0.4631 1 0; -0.2114 -.3299 0.0047 1];
U=[5.2500 -2.9500 -0.9500 -3.8000; 0 3.8914 2.3757 0.4129; 0 0 -1.5139 0.2948; 0 0 0 0.1314]
经过验证PLU=A;


4. dgesvx函数
dgesvx是expert dgesv函数,该函数可以返回更多的中间结果,如计算矩阵A的条件数,估计解的误差范围等等,相应的,函数也增加了很多参数,所以占用的内存也就更多。具体使用可以参见user book http://www.netlib.org/lapack/lug/node26.html和应用举例 http://www.nag.co.uk/lapack-ex/node6.html#DGESVX