簡體   English   中英

在Fortran中讀寫表

[英]Reading and Writing Tables in Fortran

我有一個日歷表,上面有上升時間和設定時間

   Jan       Feb     ....    Dec
rise set  rise set   .... rise set
0643 1754 0433 1305  .... 1256 0219
1057 2230 1038 9999  .... 1502 0151
0912 9999 1026 0139  .... 1559 0103
1147 0149            .... 1739 0130

(不必擔心9999,以后再處理。2月底的空白表示該日期不存在。)

顯然,我不想一次將整個年度加載到一個數組中(試圖在任何給定的時間段確定DOY時將是一場噩夢),我想一次處理兩列數據。腳本,其變量格式如下:

26     format(<iskip>X,I2,3X,I2)
       idoy=001
       iskip=4
       irise1=00
4      read(1,26,end=6,err=4)irise2,iset2
       if (irise2.eq.iset2) go to 6    !if both blank, move to next column
7      irise1=irise2
       iset1=iset2
       irise2=99
       iset2=99
       idoy++
       go to 4

6      iskip=iskip+11
       irise1=irise2
       iset1=iset2
       irise2=99
       iset2=99
       idoy++
       if (iskip.lt.128) go to 4

基本上,該程序將一次讀取兩列,存儲數據並跟蹤一年中的某天。

為了試驗使用格式變量的想法,我創建了一個測試程序,該程序打印出一個10x24的值矩陣,看起來應該像DOYHH逐列:

    integer idoy,ihour,iskip

    idoy=1
    ihour=0
    iskip=0

    do while (idoy.le.10)
            do while (ihour.lt.24)
 2                  format(<iskip>X,I3,I2)
                    write(2,2)idoy,ihour
            end do
            iskip=iskip+6
    end do
    end

但是f77和f95的編譯器對此確實感到不滿意。 關於如何使測試程序正常工作的任何建議? 我可能可以從那里推斷技術。 同樣,將測試程序寫入矩陣的底部,然后從頂部重新啟動,這一點非常重要。

來自F77的錯誤消息:

test.f: In program `MAIN__':
test.f:9:
    2                  format(<iskip>X,I3,I2)
                                     ^
Variable-expression FORMAT specifier at (^) -- unsupported

來自F95的錯誤消息:

test.f:9.16:
 2  format(<iskip>X,I3,I2)
           1
Error: Unexpected element '<' in format string at (1)
test.f:10.17:

    write(2,2)idoy,ihour
            1
Error: FORMAT label 2 at (1) not defined

類似的問題在這里: 可變格式

我不確定如何使用他們的解決方案。 有人可以針對這種問題發布通用格式嗎?

有幾種可能的方法,下面我將介紹三種模式。


[ 第一種方法 ]正如課題中所建議的那樣,人們一次讀取兩列。 假設每年有4天零3個月的樣本輸入,並且每次以'(I5)'格式編寫,

   Jan       Feb    June
 rise set  rise set  rise set
 0643 1754 0433 1305 1256 0219
 1057 2230 1038 9999 1502 0151
 0912 9999           1559 0103
 1147 0149

我們可以讀為

integer, parameter :: Nday = 4, Nmon = 3   !! for actual data, Nday = 31 and Nmon = 12
integer, dimension( Nday, Nmon ) :: rise, set
integer :: d, m
character(200) :: lineskip

open( 10, file="time_blank.dat", status="old" )

do m = 1, Nmon
    rewind( 10 )
    read( 10, * ); read( 10, * )  !! skip the two header lines

    do d = 1, Nday
        read( 10, "(a, 2i5)" ) &
                lineskip( 1 : 10 * (m-1) ), rise( d, m ), set( d, m )
    enddo
enddo
close( 10 )

在這里,我們使用lineskip (虛擬字符串)跳過已處理的數據。 請注意, rise and set for empty field設置為0 ,根據情況可能不理想。


[ 第二種方法 ]將每一行讀入一個字符串,然后解析它以獲得整數數據。 例如,

integer :: offset
character(1000) :: line
character(5) :: str1, str2

rise(:,:) = -1 ; set(:,:) = -1   !! first, initialize all data with dummy values
...
do d = 1, Nday
    read( 10, "(a)" ) line

    do m = 1, Nmon
        offset = 10 * (m-1)
        str1 = line( offset + 1 : offset + 5  )
        str2 = line( offset + 6 : offset + 10 )
        if ( str1 /= "" ) read( str1, * ) rise( d, m )
        if ( str2 /= "" ) read( str2, * ) set ( d, m )
    enddo
enddo

其中將每一行讀入line ,划分為字段,然后提取整數值(如果有)。 在這里,為空數據設置riseset為用戶定義的虛擬值(此處為-1 )。 也可以使用類似的方法來改進第一種方法。


[ 第三種方法 ]有時使用自由格式的輸入文件更為方便。 為此,讓我們用空值填充空數據,例如-1:

Jan           Feb         June
rise  set     rise  set      rise set
0643  1754    0433  1305   1256 0219
1057  2230    1038  9999    1502 0151
0912  9999    -1    -1     1559 0103
1147  0149    -1    -1        -1   -1   <--- free format

然后我們可以一次讀取所有數據

open( 10, file="time_filled.dat", status="old" )
read( 10, * )   !! skip the header
read( 10, * )
read( 10, * ) ( ( rise( d, m ), set( d, m ), m=1,Nmon ), d=1,Nday )
close( 10 )

IMO,這是最簡單,最靈活的方法,只要我們可以修改輸入文件即可。


[ 序列化數據 ]可以序列化riseset為DOY的函數

idoy = 0
do m = 1, Nmon
do d = 1, Nday
    if ( rise( d, m ) >= 0 ) then    !! assuming the dummy value = -1
        idoy = idoy + 1
        print *, idoy, rise( d, m ), set( d, m )
    endif
enddo
enddo

或使用pack功能:

integer, allocatable :: rise_doy(:), set_doy(:)

rise_doy = pack( rise, rise >= 0 )  !! assuming the dummy value = -1
set_doy  = pack( set,  set  >= 0 )

(請注意,對於Intel fortran,我們需要-assume realloc_lhs選項)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM