用于创建空间网格的程序,属于网格内的平均值,写入表

时间:2015-05-22 04:20:08

标签: fortran astronomy

所以我试图想出一个聪明的方法来让这个程序读取目录并将任何属于特定空间“网格”框的内容放在一起,并将该框中的数据平均在一起。我会在下面粘贴我的可怕尝试,希望你会看到我正在尝试做什么。我无法使程序正常工作(它被困在一个我没有调试过的循环中),而且在我再次撞击它之前我想知道这是否看起来像是一个逻辑的操作集合我希望这样做,或者是否有更好的方法来实现这一目标。

编辑:为了澄清,参数部分用于修剪参数---“lmin lmax bmin bmax”设置整体框架,“deg”设置平方度增量。

program redgrid

implicit none

! Variable declarations and settings:
integer :: ncrt, c, i, j, k, count, n, iarg, D, db, cn
real :: dsun, pma, pmd, epma, epmd, ra, dec, degbin
real :: V, Per, Amp, FeH, EBV, Dm, Fi, FeHav, EBVav
real :: lmin, lmax, bmin, bmax, l, b, deg, lbin, bbin
real :: bbinmax, bbinmin, lbinmax, lbinmin
character(len=60) :: infile, outfile, word, name
parameter(D=20000)
dimension :: EBV(D), FeH(D), lbinmax(D), bbinmax(D)
dimension :: bbinmin(D), lbinmin(D)
103 format(1x,i6,4x,f6.2,4x,f6.2,4x,f7.2,3x,f6.2,4x,f5.2,4x,f5.2,4x,f5.2,4x,f6.4)

3 continue
iarg=iargc()
if(iarg.lt.7) then
 print*, 'Usage: redgrid infile outfile lmin lmax bmin bmax square_deg'
 stop
 endif
 call getarg(1, infile)
 call getarg(2, outfile)
 call getarg(3, word)
 read(word,*) lmin
 call getarg(4, word)
 read(word,*) lmax
 call getarg(5, word)
 read(word,*) bmin
 call getarg(6, word)
 read(word,*) bmax
 call getarg(7, word)
 read(word,*) deg

open(unit=1,file=infile,status='old',err=3)
open(unit=2,file=outfile,status='unknown')

write(2,*)"| l center | b center | [Fe/H] avg | E(B-V) avg | "

 FeHav = 0.0
 EBVav = 0.0
 lbinmin(1) = lmin
 bbinmin(1) = bmin
 degbin = (bmax-bmin)/deg
 db = NINT(degbin)
 do j = 1, db
    bbinmax(j) = bbinmin(j) + deg
    lbinmax(j) = lbinmin(j)*cos(bbinmax(j))
    print*, lbinmin(j), bbinmin(j), db
    cn = 1
           7 continue
           read(1,*,err=7,end=8) ncrt, ra, dec, l, b,&
                V, dsun, FeH(cn), EBV(cn)
           if(b.ge.bbinmin(j).and.b.lt.bbinmax(j)) then
              if(l.ge.lbinmin(j).and.l.lt.lbinmax(j)) then
                 FeHav = FeHav + FeH(cn)
                 EBVav = EBVav + EBV(cn)
                 cn = cn + 1
              end if
           end if
           goto 7
           8 continue
           FeHav = FeHav/cn
           EBVav = EBVav/cn
           write(2,*) lbinmax(j), bbinmax(j), FeHav, EBVav
           bbinmin(j+1) = bbinmin(j) + deg
           lbinmin(j+1) = lbinmin(j) + deg
        end do

close(1)
close(2)

end program redgrid

以下是我正在使用的表格的一小部分。 “l”和“b”是我正在使用的两个坐标---它们是有角度的,因此需要使网格分量为“b”和“l * cos(b)”。对于每个0.5 x 0.5度的截面,我需要在该块内具有E(B-V)和[Fe / H]的平均值。当我写文件时,我只需要四列:盒子所在的两个坐标,以及该盒子的两个平均值。

| Ncrt  | ra      | dec     | l       | b       | V      | dkpc   | [Fe/H] | E(B-V) | 
7888    216.53    -43.85     -39.56    15.78    15.68     8.90    -1.19    0.1420
7889    217.49    -43.13     -38.61    16.18    16.15    10.67    -1.15    0.1750
7893    219.16    -43.26     -37.50    15.58    15.38     7.79    -1.40    0.1580

现在,程序在循环周期的某个地方卡住了。我粘贴了运行它时发生的终端输出,以及我运行它的命令行。如果我能帮忙澄清,请告诉我。对于像我这样的Fortran新秀来说这是一个非常复杂的问题 - 也许我错过了一些让它变得容易的基础知识。无论如何,提前谢谢。

./redgrid table2.above redtest.trim -40 0 15 30 0.5
 -40.0000000       15.0000000              30   0.00000000       0.00000000    
 -39.5000000       15.5000000              30  -1.18592596      0.353437036    

^它在两行后卡住了。

1 个答案:

答案 0 :(得分:0)

我认为该程序可以执行您希望它执行的操作,但您正在寻找一些可以整理代码的方法。

首先,我会修复缩进。

其次,我不会使用低于10的单位数。

INTEGER, PARAMETER :: in_unit = 100
INTEGER, PARAMETER :: out_unit = 101
...
OPEN(unit=in_unit, file=infile, status='OLD")
...
READ(in_unit, *) ...
...
CLOSE(in_unit)

第三,我不会使用GOTO和标签。你可以更容易地在循环中做到这一点:

INTEGER :: read_status

DO j = 1, db
    ...
    read_loop : DO
        READ(in_unit, *, IOSTAT=read_status) ...
        IF (read_status == -1) THEN    ! EOF
            EXIT read_loop
        ELSEIF (read_status /= 0) THEN
            CYCLE read_loop
        ENDIF
        ...
    END DO read_loop
    ...
END DO

您的代码中存在一些危险,即使在上面的这一个中:它可能导致无限循环。例如,如果infile的开头失败(例如文件不存在),它会循环回标签3,但没有任何变化,因此最终会再次尝试打开同一个文件,并且可能会同样的错误。

同上:如果READ在没有前进的情况下反复失败,并且错误不是EOF,那么读取循环将不会终止。

你必须考虑你希望你的程序在发生这样的事情时做什么,并对其进行编码。(例如:如果无法打开文件,则打印错误消息和STOP。)

你有一个很长的FORMAT声明。你可以这样离开,虽然我可能会尝试缩短它:

103 FORMAT(I7, 2F10.2, F11.2, 4F9.2, F10.4)

这应该是同一行,因为数字通常是右对齐的。您还可以使用字符串作为格式,因此您也可以执行以下操作:

CHARACTER(LEN=*), PARAMETER :: data_out_form = &
                '(I7, 2F10.2, F11.2, 4F9.2, F10.4)'

WRITE(*, data_out_form) var1, var2, var3, ...

再次,这是一个较少的标签。