Fortran Coder

查看: 34465|回复: 33
打印 上一主题 下一主题

[求助] 一个计算相关的编程思路/方法讨论

[复制链接]

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
跳转到指定楼层
楼主
发表于 2015-3-23 20:19:38 | 显示全部楼层 回帖奖励 |倒序浏览 |阅读模式
最近在算rotation matrix elemetns相关的,其中有一条是closure的check。具体数学公式之类不详细解释,换成通俗语言问题是这样的:

文件A: 有160个数据,分别是x1(i),y1(i),z1(i)

文件B: 有160个数据,分别是x2(i),y2(i),z2(i)

经过简单运算,二文件数据之差是 x(i),y(i),z(i)

现有S=3(COS(X)^2-1)/2的计算公式,其中COS(X)^2是由x(i),y(i),z(i)运算得来。^是平方符号

现在已经写好的程序是这样的:
[Fortran] 纯文本查看 复制代码
program main
    implicit none

    integer i,j
    integer ios
    integer m,n
    character(160) :: filename1,filename2,filename3,filename4,tmp 
    integer id
    integer n1,n2
    real x1,y1,z1
    real x2,y2,z2
    real x(10000),y(10000),z(10000)
    real v1,v2,v3
    real a,b,c
    real up,down,coss(10000),s1(10000),s2(10000),s3(10000),avg
      integer GetFileN,ii,jj
    character(len=10)::status


    print*, 'Running...'
      filename1='c6_'
      filename2='c8_'
      do m=1,1   ! number of files to read
      write(tmp,*)m             
      open(10,file=trim(filename1)//trim(adjustl(tmp))
    1//'.dat',status='old' )
      open(20,file=trim(filename2)//trim(adjustl(tmp))
    1//'.dat',status='old' )
      do i=1,GetFileN(10) 
    read(10,*,iostat=ios) n1,x1,y1,z1   !read c6
    read(20,*,iostat=ios) n2,x2,y2,z2   !read c8
    if (ios /=0) then
    exit
    endif
      x(i)=x2-x1    !c8-c6 x
    y(i)=y2-y1    !c8-c6 y
    z(i)=z2-z1    !c8-c6 z
c    print*,x(i),y(i),z(i)
c      write(30,'(3f12.5)')x(i),y(i),z(i)
    a=0
    b=0
    c=1 ! labframe
    up=(x(i)*a+y(i)*b+z(i)*c)*(x(i)*a+y(i)*b+z(i)*c)
    down=(x(i)*x(i)+y(i)*y(i)+z(i)*z(i))*(a*a+b*b+c*c)
    coss(i)=up/down   ! cos(i)^2
c      print*, coss(i)   
    s1(i)=(3*coss(i)-1)/2  !n=0 d00
    s2(i)=-sqrt(1.5)*sqrt(1-coss(i))*sqrt(coss(i)) ! n=1 d10
    s3(i)=sqrt(0.375)*(1-coss(i)) !n=2 d20
c    print*, s1(i) 
c     print*, s2(i)
c    print*, s3(i)
    enddo
    enddo
    print*, 'Done.'
      close(10)
      close(20)
    end

      integer function GetFileN(iFileUnit)
      implicit none
      logical , parameter :: b = .True.
      integer , intent( IN ) :: iFileUnit
      character*(1) :: c
      GetFileN = 0
      rewind( iFileUnit )
    do while (b)
      read( iFileUnit , * ,end =999 ,Err = 999 )c
      GetFileN = GetFileN + 1
      end Do
999   rewind( iFileUnit )
      return
      end function GetFileN

请忽略n1和n2,不需要他们参与计算。并且对应A和B两种文件其实每种有几万个(所以用了

trim(filename1)//trim(adjustl(tmp))
    1//'.dat')

的写法。其他s2和s3是指另外两个需要计算的公式。

因为最后需要对这几万个求出的s1,s2,s3值求平均,用现在的写法计算起来超!慢(这里特别说明一下,因为需要统计上有效,所以实际上还要取不同的间隔。比如文件A1,A2这种间隔为1的,下面还要计算A1,A3这样间隔为2的......直到达到文件总数的一半为止(比方说总共10个文件,实际要重复计算五次,间隔分别是1,2,3,4,5。我之前用过的一种‘土办法’是把每一个n对应的xyz提取出来单独存成另一个文件,用另一个程序计算: 见下面)。所以现在需要超过一天以上的时间完成全部运算!)。我想请教各位有没有别的办法可以实现更快的计算,谢谢!

---土办法---
[Fortran] 纯文本查看 复制代码
print*, 'Please enter the number of files:'
      read*,nn
          do mm=1,nn
        write(tmp,*)mm         
      open(10,file=trim('S (')//trim(adjustl(tmp))//').dat'
    1,status='old')
c      open(10,file='nozero3534.dat',status='old')         
      num=GetFileN(10)
      allocate(a(num,3))  
      allocate(b(num,3))
    allocate(c(num))
    allocate(x1(num))
allocate(y1(num))
    allocate(z1(num))
    allocate(x2(num))
    allocate(y2(num))
    allocate(z2(num))
    allocate(up1(num))
    allocate(below1(num))
    allocate(cos21(num))
    allocate(up2(num))
    allocate(below2(num))
    allocate(cos22(num))
    allocate(s(num))
    allocate(summ(num))
    allocate(avg(num))
      do n=1,num
    read(10,*,iostat=ios) (a(n,m), m=1,3) 
    if(ios/=0) then
    exit
    endif
    enddo 

      do step=1,NUM/2
      summ=0
do j=1,NUM-step    
      B(j,:)=A(step+j,:)
      x1(j)=a(j,1)
    y1(j)=a(j,2)
    z1(j)=a(j,3)
      up1(j)=z1(j)*z1(j)
    below1(j)=x1(j)*x1(j)+y1(j)*y1(j)+z1(j)*z1(j)
    cos21(j)=up1(j)/below1(j)
      x2(j)=b(j,1)
    y2(j)=b(j,2)
    z2(j)=b(j,3)
      up2(j)=z2(j)*z2(j)
    below2(j)=x2(j)*x2(j)+y2(j)*y2(j)+z2(j)*z2(j)
    cos22(j)=up2(j)/below2(j)
      s(j)=cos21(j)*cos22(j)
    summ=s(j)+summ
    enddo
    avg=summ(j)/(num-step)



分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
沙发
 楼主| 发表于 2015-3-23 23:28:28 | 显示全部楼层
li913 发表于 2015-3-23 22:21
上面的代码,主题结构没啥可更改的了,适当优化一下。比如
up=(x(i)*a+y(i)*b+z(i)*c)*(x(i)*a+y(i)*b+z(i) ...

非常感谢!
我试了一下你的代码,遇到一个小问题:

对应coss(i)=up/down语句。之前的部分我有逐一检查过。
------
另外就是关于下面的统计部分,您有其他好办法可以让这两个程序写在一起吗? 比如说,对应这样的计算(就是您给优化过的那个),能不能直接选择file的间隔? 现在是按顺序一个接一个读,A1之后是A2,A3......能不能跳着读? 就是先一个接一个,然后每隔两个,每隔三个,重复同样的计算,一直到全部文件数的一半。我只会下面那个土办法,就是先提取出来,然后用j=1, num-step这样的。这个办法可以用,但是太慢了。我不知道怎样能把它们写在一起。

恳请您的指导!

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
板凳
 楼主| 发表于 2015-3-24 17:40:17 | 显示全部楼层
pasuka 发表于 2015-3-24 08:37
为啥不是数据完全读入后,向量化操作呢?边读取边计算的话,编译器没法很好滴优化
lz一点profile的经验也 ...

您要有好办法就请您用代码介绍介绍,这样我和其他看帖子的人都能尝试运行一下比较哪种更好。我是职业研究数学的,不是职业程序员,学这个就是自己的兴趣。另外麻烦您说话客气点儿。

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
地板
 楼主| 发表于 2015-3-24 22:32:07 | 显示全部楼层
fcode 发表于 2015-3-24 21:51
没有人是职业玩 fortran 的。你,我,pasuka 都不是。

楼上的说话一贯就是这样,习惯了就好了。倒是不必 ...

我就是不喜欢上来就摆出教育人的口气说‘你该多看看书’,‘你应该怎样怎样’,‘你怎么样怎么样’,‘你没经验’之类不负责任的话。别人提一个问题,如果你知道又愿意,就请告诉答案。不愿意的话不回答就是了。假设一个学生问我怎么解一道题,他肯定不愿意听见‘你回去看看课本就知道了’这种话,他肯定希望我一步一步解出来给他看解法。公共网路,也应该抱持礼貌客气,您说是吧。

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
5#
 楼主| 发表于 2015-3-24 22:41:53 | 显示全部楼层
pasuka 发表于 2015-3-24 21:58
最初搞计算机的可都是学数学出身的,国外的图灵、冯诺依曼不提,国内的103机还是数学家华罗庚在中科院数 ...

中国国内我不了解,但我生活的国家不碰编程的纯数学家可是大有人在。有人计算机都不碰,手写论文,学生打进电脑。学习过程中,导师一概要求手脑计算,不得用电脑。我中文不好,但是仔细看一看发言,没觉得哪儿‘任性’。我表达的是: 我是一个专门学习数学知识的人,不擅长编程,也不太花时间去深入钻研编程方法。当然,如果谁有高明的code,还是乐意看一看学一学,可是请您别擅自评论我。倒是您,上来就说我们是‘无头苍蝇’,真的,不知道是谁奚落谁。要是像fcode同学说的那样,您平时就这么说话,我想我们还是别交流的好些。我习惯每天请啊您啊谢谢啊这样的讲话,习惯问题。

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
6#
 楼主| 发表于 2015-3-25 19:22:08 | 显示全部楼层
不能把缺乏教养和礼貌当成个性,我觉得您认识的那个‘老外’是非常失礼的,在我的国家,这种人会被学生投诉‘歧视’而丢掉工作。他自己喜欢,不代表别人喜欢,也不能作为常识性的标准。我欣赏的中国作家的一位世界级作家,他有一次谈论网络,他说话像写小说一样犀利,他大意说‘人一上网,就脸都不要了’。早些年电脑没有这样普及的时候,bbs不是这样的,绝大多数人都能使用礼貌用语交谈,并且讨论多半都有趣和愉快。现在网路上的中文越来越糟糕了,很多情况词的用法都很古怪,完全读不懂究竟想说什么。我希望在这个论坛上的各位都能尽量使用优美的中文,正确地表达自己的想法。

不知道您有没有教学经验(我自己做过TA),就算教科书上有,不等于人人可以读。比如一个化学系的人来问问题,我肯定不会建议去读数学书。更不会像某些人那样,‘你一点数学知识都没有吧? Gamma Funtion都不知道还念什么博士? 你是笨蛋菜鸟吗!’就算是再简单的问题,我都只能这样说,‘这个知识点您以前可能不太注意,现在给您讲解一下。’如果我不愿意讲,我会直接拒绝。

---
有没有职业编程的人呢? 我回去仔细想了一下,发现还真有。我的一个同学是制作游戏的,她每天的工作就是编写调试程序。当然,这个‘职业’,是指靠此谋生的意思。如果让她自己说,很可能回答职业是‘饲养宠物猫’。

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
7#
 楼主| 发表于 2015-3-25 21:17:26 | 显示全部楼层
fcode 发表于 2015-3-25 19:57
中国自古就是礼仪之邦,其实几千年来,大多数人还是比较讲究礼仪的。日本的文化里也是比较注重教养和礼仪的 ...

我想这是文化差异问题,在我生活的国家,就算学习好别人也不会觉得你有权力对学习不好的人做负面评价。对博士生来说,(我们组的要求)是先做好人,再做学问。无论跟谁都用sie(您)讲话,这样即使小朋友听了,也会自然学习优美的语言,将它变成一种习惯。我们的社会通常比较单纯,也就是中国人说的‘傻老外’,做学问的人通常都很和气。就算学生问了一个真正的蠢问题,也不会觉得恼火,你可以反过来想,现在他总算知道正确答案了。要知道别人可能在其他方面很优秀,有游泳的世界冠军,短跑的世界冠军,但这些人在您和我的专业范围内几乎是0基础。倘若他们愿意加入,我认为我们应该宽容地对待。

现在像您这样能够认真思考并且在(中文为主的)论坛上发表意见的人不太多了,要知道,我第一次收到’不明觉厉‘的回答时候甚至跑去查字典! 后来发现这在中文论坛是’基本常识‘。

方便的话,我能麻烦您看一下这个程序吗 (就是主题里提到的’土办法‘)? 对于9300个数据进行计算,花费1089s。我希望能更快的运算,但没有(能够)使得它变好的任何经验。目前来说我可以完成一项普通程度的编程工作,但不能用最短时间完成,而这也是我很感兴趣的部分。
[Fortran] 纯文本查看 复制代码
program main
       implicit none  
       integer,parameter::file_number= 1
       character(100)::tmp
         character(160)::fileN
       character(100)::filename(file_number)
         integer::i,j,k,m,n,NUM,step,ios,ntotal
         integer::p,q,GetFileN
       real,pointer::A(:,:),B(:,:),c(:)
         real,pointer::x1(:)
         real,pointer::y1(:)
         real,pointer::z1(:)
         real,pointer::x2(:)
         real,pointer::y2(:)
         real,pointer::z2(:)
         real,pointer::up(:)
         real,pointer::below(:)
         real,pointer::cos2(:)
         real,pointer::s(:)
         real,pointer::summ(:)
         real,pointer::avg(:)
       real*8 time
       integer*4 time0, time1, dtime

 c Start time
       call system_clock(time0)

       open(10,file='testdata.dat',status='old')             
       num=GetFileN(10)
       allocate(a(num,3))  
       allocate(b(num,3))
         allocate(c(num))
         allocate(x1(num))
         allocate(y1(num))
         allocate(z1(num))
         allocate(x2(num))
         allocate(y2(num))
         allocate(z2(num))
         allocate(up(num))
         allocate(below(num))
         allocate(cos2(num))
         allocate(s(num))
         allocate(summ(num))
         allocate(avg(num))
       do n=1,num
         read(10,*,iostat=ios) (a(n,m), m=1,3) 
         if(ios/=0) then
         exit
         endif
 c         write(6,'(f8.3,f8.3,f8.3)')(a(n,m), m=1,3) 
         enddo 
       Print*, 'Running...'
       do step=1,NUM/2
       summ=0
       do j=1,NUM-step     
 c      write(tmp,"(i4.4)")step
       B(j,:)=A(step+j,:)
 c        print*, A(j,:)
 c        print*, B(j,:)
       x1(j)=a(j,1)
         y1(j)=a(j,2)
         z1(j)=a(j,3)
       x2(j)=b(j,1)
         y2(j)=b(j,2)
         z2(j)=b(j,3)
       up(j)=(x1(j)*x2(j)+y1(j)*y2(j)+z1(j)*z2(j))**2
         below(j)=(x1(j)*x1(j)+y1(j)*y1(j)+z1(j)*z1(j))*(x2(j)*x2(j)
         1+y2(j)*y2(j)+z2(j)*z2(j))
         cos2(j)=up(j)/below(j)
         s(j)=(3*cos2(j)-1)/2
         summ=s(j)+summ
         enddo
 c      print*, summ(j)
         avg=summ(j)/(num-step)
 c        print*, (num-step)
 c        print*, avg(j)
       open(20,file='testresult.dat',status='unknown')
       write(20,222)avg(j)

         enddo   ! enddo for 'tmp'=>step

 111   format (3f8.3)
 222   format (f12.6)
       close(10)
       deallocate(A,B,C)          
         deallocate(x1,y1,z1,x2,y2,z2,up,below,cos2,s,summ,avg)
 c Finish time
       call system_clock(time1, dtime)
 c Output time
       time = 1d0*(time1-time0)/dtime
       write(*,"(a7,f16.7)")"Time = ",time
       end

       integer function GetFileN(iFileUnit)
       implicit none
       logical , parameter :: b = .True.
       integer , intent( IN ) :: iFileUnit
       character*(1) :: c
       GetFileN = 0
       rewind( iFileUnit )
         do while (b)
       read( iFileUnit , * ,end =999 ,Err = 999 )c
       GetFileN = GetFileN + 1
       end Do
 999   rewind( iFileUnit )
       return
       end function GetFileN

数据是这样的:

0        0        1
21.086        0.082        21.079
20.531        -0.909        20.161
19.106        -0.566        19.855
18.938        -0.763        21.644
19.99        -2.14        22.666
...
(total=9300)

感谢您花费时间,并且感谢您的帮忙!

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
8#
 楼主| 发表于 2015-3-25 21:33:25 | 显示全部楼层
以下是全部的9300个数据,再次感谢您的帮助!

---
第一次学会发送‘附件’!

testdata.TXT

189.07 KB, 下载次数: 9

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
9#
 楼主| 发表于 2015-3-25 21:35:03 | 显示全部楼层
fcode 发表于 2015-3-25 21:23
我建议你把 9300 个数据传上来。
(编辑框里如果有字数限制,可以用附件上传) ...

全部数据已经用附件上传,经过我个人测试是可以正确下载的。

再次感谢您的帮忙。

46

帖子

8

主题

0

精华

熟手

F 币
211 元
贡献
131 点
10#
 楼主| 发表于 2015-3-25 22:23:53 | 显示全部楼层
fcode 发表于 2015-3-25 22:06
Running...
Time =        7.8090000

试验以后难以表达我的喜悦之感!!! 现在我可以用fs为单位进行计算了(对精确的追求方面有些神经质)。您说得对,这个是correlation function (绝大多数专业词我不会用中文表达,非常抱歉)相关的计算。就是Satchler那本Anguler Momentum147页提到的closure部分的验证。这个角度cos(theta)是stochastic quantity里面的一个时间相关的参数(我表达的不好,可能词不达意)。为了统计上的精确,不但时间间隔取1,还要取2,取3.....假设时间为10,那么要取到至少间隔5; 就是用第一个数据和第六个数据计算,第二个数据和第七个数据计算.....以此类推。就结果本身来说其实没有特别大的差别,但如果plot出来就会发现如果不这样图像会出现锯齿,而不是smooth的。
---
我能不能请教您,我其实看不太出来究竟是哪里的修改起了关健性的作用。为什么计算时间会相差上百倍? 能不能请您简单地谈一谈,根据经验,如何能在做这类步骤很多的重复的计算时优化速度。非常感谢!!!
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-5-6 14:32

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表