Fortran 程序创建空间网格,将网格内的平均值写入表格

Fortran 程序创建空间网格,将网格内的平均值写入表格,fortran,astronomy,Fortran,Astronomy,因此,我试图想出一个聪明的方法,让这个程序读取一个目录,并将特定空间网格框内的所有数据取平均值。我将把我可怕的尝试贴在下面,希望你能看到我在尝试做什么。我无法让程序正常运行,它陷入了一个我没有调试过的循环中,在我再次尝试之前,我想知道这是否是我想要做的事情的一组逻辑操作,或者是否有更好的方法来实现这一点 编辑:为了澄清,参数部分用于修剪参数——lmin lmax bmin bmax设置整体框架,deg设置平方度增量 program redgrid implicit none ! Variab

因此,我试图想出一个聪明的方法,让这个程序读取一个目录,并将特定空间网格框内的所有数据取平均值。我将把我可怕的尝试贴在下面,希望你能看到我在尝试做什么。我无法让程序正常运行,它陷入了一个我没有调试过的循环中,在我再次尝试之前,我想知道这是否是我想要做的事情的一组逻辑操作,或者是否有更好的方法来实现这一点

编辑:为了澄清,参数部分用于修剪参数——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*cosb。对于每个0.5 x 0.5度的截面,我需要该块内的EB-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    

^两行代码之后,它就卡住了。

我假设程序做了您希望它做的事情,但是您正在寻找一些东西来整理代码

首先,我要修复压痕

第二,我不会使用低于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)
第三,我不会使用GOTOs和标签。您可以在循环中轻松地执行此操作:

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
在您的代码中,甚至在上面的代码中,也存在一些危险:它可能导致无限循环。例如,如果infle的打开失败,例如文件不存在,它将循环回标签3,但没有任何更改,因此它最终将再次尝试打开同一文件,并且可能会出现相同的错误

如上所述:如果读取重复失败而不前进,并且错误不是EOF,则读取循环将不会终止

当类似的事情发生时,您必须考虑您希望您的程序做什么,并编写代码。例如:打印错误消息,如果无法打开文件,则停止

你有一个很长的格式声明。你可以这样留着,不过我可能会尽量把它缩短一点:

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, ...

再一次,这少了一个标签。

谢谢,我感谢你的回复,我一定会尝试整理一下你的建议。我想我忘了在现在编辑的主要帖子中具体说明,因为程序还没有运行,我也不确定我列出的方法是否符合逻辑。因此,在对read_循环进行了一些修补和实现之后,我让它运行起来。非常感谢——阅读循环是我不知道的,它非常有用。这不是问题,但它帮助我隔离了问题。问题是,在文件开始时,我打开了infle,因此当它在循环一次之后读取文件时,它将没有更多的行并冻结。它打印两行的原因是因为print命令出现在第二次读取尝试之前。需要注意的是:我使用的Fortran手册中有end=和err=语句,它们都标有“请勿使用大危险”。我真的认为应该使用IOSTAT和IOMSG参数。顺便说一下:read_循环是一个名称,因此它可以是任何名称,但必须在范围内是唯一的。