Fortranで33年の平均値を導く際のエラー

このQ&Aのポイント
  • Fortranを使用して33年の平均値を導くプログラムでエラーが発生しています。
  • エラーの原因は、14161が2008年まで存在しない可能性があります。
  • アドバイスや修正すべき箇所があれば助かります。
回答を見る
  • ベストアンサー

fortranについての質問です。

fortranについての質問です。 このFortranは、頭にそれぞれ14161~14163とつく33個のファイル(1/1~12/31,欠損地あり1年分)を読んでいき、例えば1/1、1/2…と365日分の33年の平均値を導くはずなのですが、下のようなエラーがでます。おそらく、14161が2008までないからではないかと思うのですが、現在勉強中なので、なにかアドバイス、おかしいところ修正できるところがありましたらお願いします。 program sapporo_kikouchi    INTEGER :: sum, no, point INTEGER :: year, mon, day, data INTEGER :: doy REAL,dimension(365) :: temp, ndata REAL :: lon, lat CHARACTER*4 yyyy CHARACTER*5 sssss ndata(:)=0.0 temp(:)=0.0 do ispot=14161,14163 write(sssss,"(i5)") ispot do iwork=1976, 2008 write(yyyy,"(i4.4)") iwork open(50, file=''//sssss//'_temp'//yyyy//'.csv', status='old') ! write(6,*) ispot iwork    do i = 1,366 read(50,*,iostat=io) id,year,mon,day,lon,lat,data if(io < 0) exit if(mon==2 .AND. day==29) then cycle endif call date2doy(year,mon,day,doy) temp(doy) = temp(doy) + data/10.0 ndata(doy) = ndata(doy) + 1 end do close(50) enddo !!! end of year loop enddo do i=1,365 if( ndata(i) == 0 ) then temp(i) = -99999.9 else temp(i)=temp(i)/ndata(i) endif write(6,*) i, temp(i), ndata(i) enddo stop end program subroutine date2doy(iy,im,id,idoy) INTEGER,dimension(12) :: nday INTEGER :: uruu !!uruu=1: うるう年、uruu=0: 通常の年 uruu=0 DATA nday /31,28,31,30,31,30,31,31,30,31,30,31/ if(mod(iy,4)==0 .AND. mod(iy,100)/=0) then uruu=1 endif if(mod(iy,1000)==0) then uruu=1 endif !! うるう年も無視する itotal = 0 if( im /= 1 )then do m=1, im-1 itotal = itotal + nday(m) enddo endif idoy = id + itotal ! write(6,*) iy,im,id, idoy return end ------------------------------------------------------------------------------ At line 18 of file kikouchi.f90 file: "14161_temp1993.csv" Traceback: not available, compile with -ftrace=frame or -ftrace=full Fortran runtime error: 指定されたファイルが見つかりません。 -------------------------------------------------------------------------------

  • ryoji
  • お礼率57% (90/156)

質問者が選んだベストアンサー

  • ベストアンサー
  • f272
  • ベストアンサー率46% (7992/17078)
回答No.3

> 一度、iostat=ioをOPEN文に指定せずif (io < 0) cycleと書いたときは、同じようなエラーがでたのですが それはそうでしょう。OPEN文を実行したときのステータスをどの変数に設定すればよいのか教えてもいないのに,ioという変数を見ても仕方がありません。 > if文のなか(io < 0)でも(io /= 0)でも回りました。あまり差はないんですかね? 正常に開けたときは0になって,そうでない場合は正の整数が返ります。負の値が返るのはあなたの使っているシステムの拡張機能ではないですか?なんにせよエラーの原因に興味がないときには0であるかどうかだけを判定すれば十分です。エラーの原因を知りたければ値がどうなっているかを調べます。 > ただ、今回回ったものの全て欠損値として出力されてしまっています。 本当にファイルの中身はあるのですか?また中身があったとしてもファイルは正常に読めているのですか?そういうことを確認すべきですね。デバッガを使うとか, read(50,*,iostat=io) id,year,mon,day,lon,lat,data の次の行に print*,id,year,mon,day,lon,lat,data とでも書いて確認してください。

ryoji
質問者

お礼

ありがとうございました。 できました。違うチェックのためにファイルを一度違うファイルのなかに隠しておいたせいでした。 本当に助かりました。 また、おそらくFRTRANについて質問すると思いますが、もし見かえることがありましたら、ぜひご教授いただけるとうれしいです。 今回はありがとうございました。

その他の回答 (2)

  • f272
  • ベストアンサー率46% (7992/17078)
回答No.2

うるう年であるのは以下の条件です。 if(mod(iy,4)==0) uruu=1 if(mod(iy,100)/=0) uruu=0 if(mod(iy,400)==0) uruu=1 もし1976年から2008年まで限定で良いのなら if(mod(iy,4)==0) uruu=1 だけで済みます。 エラーメッセージとして14161_temp1993.csvがないといわれています。 欠損値を除いた平均値を導きたいということなら open(50, file=''//sssss//'_temp'//yyyy//'.csv', status='old') でエラーとなった時にスキップするよう open(50, file=''//sssss//'_temp'//yyyy//'.csv', status='old', iostat=io) if(io /= 0) cycle とでもしておけばいいんじゃないかな。

ryoji
質問者

お礼

ありがとうございました。 一度、iostat=ioをOPEN文に指定せず if (io < 0) cycle と書いたときは、同じようなエラーがでたのですが、今回回りました。 確かめたところ、指定しないとだめなんですね。 またif文のなか(io < 0)でも(io /= 0)でも回りました。あまり差はないんですかね? ただ、今回回ったものの全て欠損値として出力されてしまっています。 1 -99999.9 0. 2 -99999.9 0. : 365 -99999.9 0. となっています。まだ修正しなければいけないところがあるようです。 なにかアドバイスあるでしょうか?

  • f272
  • ベストアンサー率46% (7992/17078)
回答No.1

エラーの原因は分かっているようですが、どのように処理したいのでしょうか? それからdate2doyでは閏年の判定らしきものをやっているが、その判定が間違っている上に、せっかくの判定を使っていないのはどうして?

ryoji
質問者

お礼

ありがとうございます。 うるう年のところ間違っていますか?どこが違いますか?確かに今回は使用しません。が、今後違う視点で見る必要が出てくるので、書いときました。先頭に!つけます。 また、今回の最終的な目標は、上にも書きましたが、「1/1、1/2…と365日分の33年の平均値を導く」ということです。欠損値があるため、欠損値を除いた平均値を導きたいのです。 どういう処理というのはどういうことでしょうか? 画面に出力されるのは、1976~1992年までしか出力されず、 write(6,*) i, temp(i), ndata(i) の部分が出力されていないんです。 このプログラムを作ったときは、14161_temp[1976-2008]が33個、ディレクトリにあった際は回ったはずなのですが。

関連するQ&A

  • Fortranについての質問です。下のプログラムは、ある地点(今回は1

    Fortranについての質問です。下のプログラムは、ある地点(今回は14161~14163)の33年間(1976~2008)の気温の平均を欠損値を考慮してだしているはずです。うるう年の判定はおまけで書いています。 この平均値に標準偏差もつけるプログラムにしたいのですが、どう書いていいのか手詰まり中です。どうかアドバイスください。 ---------データの一部(14162_temp1997.csv)------------------------------------- 14162 1997 1 1 141.332 43.0583 -10 14162 1997 1 2 141.332 43.0583 18 14162 1997 1 3 141.332 43.0583 -2 ---------プログラム------------------------------------------------------------ program sapporo_kikouchi INTEGER :: sum, no, point INTEGER :: year, mon, day, data INTEGER :: doy REAL,dimension(365) :: temp, ndata REAL :: lon, lat CHARACTER*4 yyyy CHARACTER*5 sssss ndata(:)=0.0 temp(:)=0.0 do ispot=14161,14163 write(sssss,"(i5)") ispot do iwork=1976, 2008 write(yyyy,"(i4.4)") iwork open(50, file=''//sssss//'_temp'//yyyy//'.csv', status='old',iostat=io) if (io < 0) cycle ! write(6,*) ispot iwork   do i = 1,366 read(50,*,iostat=io) id,year,mon,day,lon,lat,data if(io < 0) exit if(mon==2 .AND. day==29) then cycle endif call date2doy(year,mon,day,doy) temp(doy) = temp(doy) + data/10.0 ndata(doy) = ndata(doy) + 1 ! doyは一年のうち何日目かを表している enddo close(50) enddo !!! end of year loop enddo do i=1,365 if( ndata(i) == 0 ) then temp(i) = -99999.9 else temp(i)=temp(i)/ndata(i) endif write(6,*) i, temp(i), ndata(i) ! write(11,*) i,',',temp(i),',',ndata(i) end do stop end program subroutine date2doy(iy,im,id,idoy) INTEGER,dimension(12) :: nday INTEGER :: uruu !!uruu=1: うるう年、uruu=0: 通常の年 uruu=0 DATA nday /31,28,31,30,31,30,31,31,30,31,30,31/ if(mod(iy,4)==0 .AND. mod(iy,100)/=0) then uruu=1 endif if(mod(iy,1000)==0) then uruu=1 endif !! うるう年も無視する itotal = 0 if( im /= 1 )then do m=1, im-1 itotal = itotal + nday(m) enddo endif idoy = id + itotal ! write(6,*) iy,im,id, idoy return end

  • FORTRANについての質問です。

    FORTRANについての質問です。 現在、二つのファイル(a.csv,b.csv)を読んで,a.csvのファイル内の地点番号とb.csvのファイル内の地点番号が一緒なら抜き出すというプログラムを書きたいのですが、途中で抜け出せなくなってしまいました。下に使用しているファイルの中身を、ごくわずかですが載せておきます。 b.csvのほうは、年別で33個のファイルに分けられています。 ----------------------a.csv------------------------------------------ 30 23226 1977 大野 31 13311 1978 増毛 31 14101 1978 新篠津 31 15251 1978 芦別 31 16281 1978 真狩 31 17076 1978 興部 ----------------------------------------------------------------------- ----------------------b.csv-------------------------------------------2006,1,1,11016,141.678,45.4147,3,稚内,0,33,16,-64,-51,-75,55,1,9 2006,1,1,11151,141.138,45.1767,14,沓形,1,20,1,-52,-36,-68,4,1,6 2006,1,1,11176,141.778,45.1017,12,豊富,0,9,4,-80,-51,-116,59,0,3 2006,1,1,11206,142.362,45.1117,13,浜頓別,1,12,13,-92,-47,-140,66,1,3 2006,1,1,11276,142.28,44.965,25,中頓別,0,5,11,-137,-44,-209,46,0,2 2006,1,1,11291,142.585,44.9397,7,北見枝幸,0,25,13,-70,-47,-94,70,0,6 2006,1,1,11316,142.48,44.84,14,歌登,0,2,1,-115,-49,-170,56,0,1 ------------------------------------------------------------------------ implicit none REAL :: number,code,year,name REAL :: yea,mon,day,id,chiki,nam INTEGER :: lon,lat,pre,wind,winddirection,temp INTEGER :: hightemp,lowtemp,sunlight,maxrain,maxwind open(10,file='a.csv',status='old',iostat=ie) do iwork=1976, 2008 write(yyyy,"(i4.4)") iwork open(50, file='b'//yyyy//'.csv', status='old', & & iostat=io) if (io < 0) cycle do i = 1, 99 read(10,*) number,code,year,name if(ie < 0) exit do ii = 1, 30000 read(50,*) yea,mon,day,id,lon,lat,chiki,nam,pre,wind,winddirection,temp,& & hightemp,lowtemp,sunlight,maxrain,maxwind if(io < 0) exit write(6,*) yea stop close(10) close(50) end エラーメッセージがenddo文が予期されている。プログラムのファイルのendが予期されていない。とでます。enddo文を足したりしても治りませんでした。おそらくどこか書き方が違うのでしょう。どうかアドバイスください。

  • fortran 途中まで考えたのですが。。。。

    エラトステネスのふるい(素数の倍数を除いていって残ったのが素数)で3桁の素数を求めて表示したいです。 私が考えたのは、 1・2~99までの数を素数かどうか調べて、素数を配列に入れていく 2・100~999まで素数の配列の中の数で割って、割り切れたらおしまい。割り切れなかったら表示していく ということです。 しかし下のプログラムではうまく素数配列ができていないようなのです。 ここまでかなり時間がかかったのでこのプログラムに手をいれて これ以外におかしくなるところもどこを直せばいいのか教えてくださるとうれしいです。 C C q223.f C PROGRAM q223 C IMPLICIT NONE C INTEGER N,i,K,s,l REAL a(99),b(99),c(99),X,Y C real M C a(1)=2 a(2)=3 l=2 C DO N=2,99,1 M=N**(0.5) S=M DO i=2,S,1 K=MOD(N,i) IF(K ==0)THEN exit ELSE IF(K /=0)THEN l=l+1 a(l)=N ENDIF ENDDO ENDDO C do N=100,999 do l=1,99 X=a(l) Y=N/X if(Y==0)then exit else if(Y/=0)then write(*,*)N end if end do end do c end よろしくおねがいします

  • アドバイスお願いします

    今,以下の様なプログラムを作っています. 正の整数nを上限とする数字の集合を考える. そのうち a*i+b*j で表現できない値の個数を出力する. a,bは事前に与えられた正の整数であり,i,jは正の整数の変数である. またa,b,nの取り得る最大値は1000000とする. とりあえずfortranで総当たりの方法で作ってみました. integer a,b,n,ans(1000000),c read(*,*)a,b,n  do i=1,n   ans(i)=i  enddo icount=0 do i=0,n  do j=0,n   c=a*i+b*j   if(c.le.n)then    do k=1,n     if(ans(k).eq.c)then      ans(k)=-1     endif    enddo   endif  enddo enddo do i=1,n  if(ans(i).gt.0)then   icount=icount+1  endif enddo write(*,*)icount end nの値があまり大きくなければ問題なく動くのですが, 最大値である1000000を入力して走らすと,とんでもなく 時間がかかってしまいます. もっとスマートな方法は無いものでしょうか? アドバイスお願い致します.

  • Fortranの素数のプログラム

    5000万までの素数を求めるプログラムなのですが、私の作ったプログラムは実行時間26秒くらいかかります。 先生が言うには10秒台が出るとのことですが、私は頑張っても時間を短くすることができません。 下に私の作ったプログラムを載せますので短くする方法を教えて下さい。 integer table(2:50000000),pno(50000000),cnt,m,i,j m=sqrt(50000000.) do 10 i=2,m do 10 j=i*2,50000000,i table(j)=1 10 continue do 20 i=2,50000000 if(table(i).eq.0)then cnt=cnt+1 end if 20 continue write(6,610)cnt 610 format('sosu no goukei =',i8) end

  • リスト構造

    Fortranでリスト構造を作ることになってしまいました。 リストに要素を追加したり、途中のデータを削除することはできたのですが、途中にデータを挿入することができません。 まだfortranバリバリ現役で打っている方、ご教授お願いします。 以下は参考です。 type element    integer ::ele    type(element),pointer ::next1 end type element type(element),pointer::root1,p1,tmp_p allocate(root1) nullify(root1%next1) p1 => root1 do i=1,n   p1%ele = a(i) !配列Aをリストへ   allocate(p1%next1)   p1 => p1%next1   nullify(p1%next1) enddo p1 => root1 print_list1:do !表示   if(associated(p1%next1))then write(*,*)p1%ele      p1 => p1%next1   else exit print_list1 endif enddo print_list1 p1 => root1 free_list1:do !解放 if(associated(p1%next1))then root1 => p1 p1 => p1%next1 deallocate(root1) else exit free_list1 endif enddo free_list1 C------ちなみに削除は delete_list:do   if(associated(p1%next1))then if(p1%ele .eq. 0)then !例えば0の要素を削除    tmp_p => p1%next1    nullify(p1%next1) deallocate(p1%next1) p1 = tmp_p else p1 => p1%next1 endif else exit delete_list endif enddo delete_list p1 => root1

  • fortran モンテカルロ法

    モンテカルロ法により円周率πを計算するプログラムを作ったのですが、以下のプログラムでモンテカルロ法から推定された円周率piの値が実行すると大きな数字になってしまって、うまく計算できてない見たです。式に問題があるのでしょうか?教えて下さい。 rogram list1_9 implicit none real(8) x, y, pi, pi0 integer :: n, i, im = 2**20 pi0 = 2.0d0*acos(0.0d0) n = 0 do i = i, im call random_number(x) call random_number(y) if(x ** 2 + y ** 2 <= 1.0d0) n = n + 1 enddo pi = 4.0d0*dble(n)/dble(im) write(*,*) ' pi, pi0, er = ', pi, pi0, pi-pi0 end program list1_9

  • fortran エラーについて

    fortranで、副プログラムを使ってデータを昇順または降順に並べ替えるプログラムを入力して実行しようとしたところ、 ・Unexpected junk in formal argument list at (1) ・Two main PROGRAMs at (1) and (2) という2つのエラーが出ました。 これらの改善方法を教えて頂きたいです。 初心者ですので簡単なところで間違えている可能性もありますが、ご指摘いただければ幸いです。 以下、実際に入力したプログラムです。 ------------------------------ implicit none integer::i,n real::x(1000),a(1000),b(1000) n=1000 open(10,file='input-data-1.txt') do i=1,n read(10,*) x(i) end do close(10) open(10,file='output-data-1.txt') do i=1,n call koukan(i,x(i),a(i),b(i)) write(10,'(i4,2f10.3)') i,a(i),b(i) end do close(10) stop end subroutine koukan(i,x(i),shoujun,koujun) implicit none integer::i,n,made real::x(1000),w,shoujun,koujun do made=n-1,1,-1 do i=1,made if(x(i)>x(i+1)) then w=x(i) x(i)=x(i+1) x(i+1)=w end if end do end do shoujun=x(i) do made=n-1,1,-1 do i=1,made if(x(i)<x(i+1)) then w=x(i) x(i)=x(i+1) x(i+1)=w end if end do end do koujun=x(i) return end ------------------------------

  • fortranのtxtファイル出力書式について

    こんにちは。 fortranのtxtファイル出力について質問させていただきます。 下記のようなコードでtxtファイルに計算結果を出力させています。(途中省略) open(20, file ='outputx1.txt') do ax1 = 1, m do ax2 = 1, l if (sum2(ax1, 1, ax2) == 1) then write(20,*) ax1, ax2 endif enddo enddo close(20) ここでm=103,l=300です。 このコードで出力すると、結果は以下のようになります。      9    293      9    294      9    295      10     97      10     98      10     99 しかし、以下のようにtxtファイルを出力したいと考えています。 9 164 9 165 9 166 10 151 10 152 10 153 *の部分を色々といじってみたのですが、うまいやり方が見つかりません。 説明不足とは思いますが、アドバイスよろしくお願いします。

  • fortran 配列受け渡し時の次元の一致

    fortran90、コンパイラはifortです。 普通メインプログラムとサブルーチン間での配列の受け渡しは、次元を揃えて渡すと思います。 とあるコード(以後コードA)を読んでいると、2次元配列を渡し、1次元配列で受け取っていました。 例 program test1 integer :: a(3,3) call testsub(a) end program subroutine testsub(b) integer :: b(9) end subroutine これが受け取り側でどう処理されているのかわからず、調べるために適当なテストコードを書きました。 a 123 456 789 ↓ b 123456789 になるとか 結果、コンパイルは通ったのですがサブルーチン側では全て0で置き換えられてしまいました。 コードAはpgiかなんかでコンパイルしていたようなのでコンパイラの違いでしょうか? よくわらなかったので質問させて頂きました。 質問をまとめますと、 (1)次元の異なる配列の受け渡しができるかどうか (2)その場合中身はどうなるか よろしくお願いします。 ---以下テストコード--- program testa implicit none integer :: a(3,3),i,j do i=1,3 do j=1,3 a(i,j)=j+(i-1)*3 enddo enddo do i=1,3 do j=1,3 write(6,*) a(i,j) enddo enddo call sub1(a) end program subroutine sub1(b) integer :: b(9),i do j=1,9 write(6,*) b(i),'sub' enddo end subroutine