باسلام

میخواستم بدونم اگه  داده های میانگین ماهانه را در برنامه ام که با زبان فرترن است بخوام فراخوانی کنم چجور این کار رو باید انجام بدم یعنی چجور یه سری ماه های خاص رو از داده هام جدا کنم مثلا ماه های تابستان 30 سال اخیر را چطور میتونم فراخوانی کنم لطفا راهنماییم بفرمایید.

ی., 13/04/2014 - 17:52
تصویر moje.am

سلام
آیا هیچ فایل توضیحی برای داده‌ها وجود داره؟ منظورم اینه که میدونید با چه ساختاری نوشته شدن؟ سوال بعد اینکه فرمت اونا ascii (اسکی) هست یا binari (دودویی)؟

تصویر anis

فایلها باپسوند
dat هستند و و با فرمت باینری ذخیره شدند

تصویر moje.am

با فرض اینکه داده‌ها در یک تراز و به صورت خطی ‌خیره شده باشند مراحل کار به صورت زیر می‌تواند باشد:

اول برخی متغیرهای مورد نیاز را تعریف می‌کنیم:

INTEGER,PARAMETER :: y=30, n=y*12
REAL*4,DIMENSION(n) :: field_in

که y تعداد کل سالهایی است که داده‌هایش را در اختیار داریم (در اینجا 30 سال)، عدد 12 تعداد ماههای سال و n تعداد کل داده‌ها خواهد بود. متغیر field_in را به طور عام به همه داده‌ها نسبت می‌دهیم.

فایل داده را با دستوری مثل زیر در برنامه آدرس دهی می‌کنیم:

OPEN(unit=300, file='mean.dat', form='unformatted', status='unknown', access='direct', recl=4*n)

که در قسمت طول رکورد (recl) ، عدد 4 دقت مورد نظر است که متناسب با دقت field_in می‌باشد.

در مرحله بعد میشود با یک خط دستور همه داده ها را خواند:

 READ(300,rec=1) field_in

سپس با استفاده از اندیس داده‌ها (از 1 تا n) از طریق مقایسه با یک شرط می‌شود فقط داد‌ه‌ ماههای خاصی که مورد نظر است جدا کرد

از هر برنامه‌ای که بخواهید استفاده کنید لازم است مثل اینجا، در آغاز همه داده‌ها را وارد کرده و سپس بخشی از آنرا جدا و استفاده کنید.

 

 

تصویر moje.am

به طور مثال، در برنامه‌ای یکی از روش‌های استخراج ماههای  موردنظر را نوشته ام.

http://paste.starnix.ir/phprmwdtn

http://paste.starnix.ir/p9gkxa4lb

در برنامه اول (test-w.f95) برای 36 ماه (3سال) اعداد 1 تا 36 در نظر گرفته و در فایل باینری به اسم mean.dat به صورت خطی و یک ترازه ذخیره می شود.

در برنامه دوم (test.f95) همین فایل، خوانده شده و فقط سه ماه تابستان (tir و mordad و shahrivar) استخراج می‌گردد.

تصویر anis

سلام 

و تشکر از پیگیریتون این کامنت اخری لینکها باز نمیشن و ارور میگیره

 

تصویر moje.am

program testo
INTEGER,PARAMETER :: y=3,n=y*12

REAL*4,DIMENSION(n) :: field_in

OPEN(unit=300, file='mean.dat', form='unformatted', status='unknown', access='direct', recl=4*n)

do i=1,n
field_in(i)=i
end do

WRITE(300,rec=1) (field_in(i),i=1,n)

end program
program testo
INTEGER,PARAMETER :: y=3, n=y*12
REAL*4,DIMENSION(n) :: field_in
REAL*4,DIMENSION(y) :: tir,mordad, shahrivar

OPEN(unit=300, file='mean.dat', form='unformatted', status='unknown', access='direct', recl=4*n)

 READ(300,rec=1) field_in
j=0		!( j+1) reffers to number of year 

do i=1,n

if (i == (4+j*12) ) tir(j+1)=field_in(i)	! for example: for  ( j=0)  =>  (i==4)  =>  tir(1)=field_in(4)  _____ 4th month of first year will be choosed and so on...

if (i == (5+j*12)) mordad(j+1)=field_in(i)

if (i == (6+j*12)) then 
shahrivar(j+1)=field_in(i)
j=j+1
end if 

end do

print*,'tir=', tir
print*,'mordad=', mordad
print*,'shahrivar=', shahrivar
end program

اگر ذخیره داده‌های شما دو بعدی باشه با ساختاری مثل لینک زیر (مقیاس قایم بر حسب سال و مقیاس افقی بر حسب ماه)، کار جداسازی داده‌ها بدون استفاده از شرط و ساده‌تر هم می‌شود

http://cri.ac.ir/files/Data/Synoptic%20Data%20up%20to%20l2005/ESFAHAN

دو برنامه زیر داده‌ها با ساختار دو بعدی را پردازش می‌کنند:

program testo
INTEGER,PARAMETER :: y=3

REAL*4,DIMENSION(12,y) :: field_in

OPEN(unit=300, file='mean.dat', form='unformatted', status='unknown', access='direct', recl=4*12*y)
n=0
do j=1,y
  do i=1,12
  n=n+1
field_in(i,j)=n
  end do
end do

WRITE(300,rec=1) ((field_in(i,j),i=1,12),j=1,y)

end program
program testo
INTEGER,PARAMETER :: y=3 
REAL*4,DIMENSION(12,y) :: field_in
REAL*4,DIMENSION(y) ::tir , mordad,shahrivar

OPEN(unit=300, file='mean.dat', form='unformatted', status='unknown', access='direct', recl=4*12*y)

 READ(300,rec=1) field_in

 
 do j=1,y

 write(*,*) (field_in(i,j),i=1,12)

 end do

 do i=1,y
 tir(i)=field_in(4,i)		! data for TIR will be choosed
 mordad(i)=field_in(5,i)
 shahrivar(i)=field_in(6,i)
 end do

print*,'tir=', tir
print*,'mordad=', mordad
print*,'shahrivar=', shahrivar
end program

 

تصویر anis

باسلام

میخواستم بدونم حالا که داده های میانگین ماهانه هرrec رو تونستم جدا کنم برای اینکه بتونم یه منطقه خاصی رو از لحاظ طول و عرض جغرافیایی جدا کنم باید field_inرو 3 بعدی تعریف میکردم  با وجودی که داده های ماهانه من یک بعدی بودند؟

باتشکر

تصویر moje.am

در این مورد مطمئن نیستم. باید دید که داده‌ها رو به چه شکل ذخیره کردن. این داده‌ها رو از کجا تهیه کردید؟

تصویر anis

سلام داده ها از سایت ncep-ncar گرفته شده

تصویر moje.am

جوابتون خیلی کلی بود.لطفا لینک داده‌ها رو بذارید تا ببینم چی هستن.اگر فرمتش مشخص بشه خوندنش کاری نداره.بعضی وقتا خود سایت میزبان یک برنامه هم برای خوندن داده‌ها میذاره!

تصویر moje.am

مشکل در واقع این هست که ما اندازه درست ابعاد آرایه داده‌ها رو نمیدونیم.

شاید بشه با  allocate کردن بفهمیم ابعاد واقعیش چقدره. قدر مسلم اینه که محور x و y  نماینده طول و عرض جغرافیایی هستند.

تصویر moje.am

من با این فایل کنترلی توی گردس می‌تونم داده‌ها رو بخونم، اما هنوز نمیفهمم ابعاد آرایه رو برای فرترن چطور تنظیم کنم.

DSET ^hgt_500_1948_2005.dat
TITLE ghashang
undef 99999
XDEF 144 linear 0 2.5
YDEF 73 linear -90 2.5 
ZDEF 1 linear 1 1
TDEF 684 LINEAR  1jan1948 1mo 
VARS 1
z 1 99 hgt
ENDVARS

 

تصویر moje.am

خودم با یه برنامه مثل این، داده‌هایی با ساختار مشابه رو خونده‌ام(کل سطح زمین بود در 23 تراز قائم و 25 زمان). اما واسه داده‌های شما هنوز جواب نداده .

program testo
        
        INTEGER,PARAMETER :: nx=144, ny=73, nz=1, y=57, nt=y*12
        INTEGER :: i,j,k,irec,tt,irec1,t
        REAL*4,DIMENSION(nx,ny) :: field_in
        REAL*8,DIMENSION(nx,ny,nz,nt) :: h
        REAL*4,DIMENSION(y):: Hjun500,Hjul500,Haug500
        
OPEN(unit=100, file='hgt_500_1948_2005.dat', form='unformatted', status='unknown', access='direct', recl=4*nx*ny*nz*nt)

  
        irec=1
        irec1=1

        DO tt=1,nt
              write(*,*)'irec=',irec
              print*,'nt=',tt
             DO k=1,nz
                 READ(100,rec=irec) field_in

                 DO j=1,ny
                    DO i=1,nx
                       h(i,j,k,tt)=field_in(i,j)
                    ENDDO                    
                 ENDDO
                 irec=irec+1
             ENDDO
             write(*,*) i,j,k,tt,h(i,j,k,tt)
	ENDDO
      

      WRITE(*,*) "Enter specific LONGITUDE (0.0E to 357.5E : 2.5 degree)"
      READ (*,*) long
      WRITE(*,*) "Enter specific LATITUDE (90.0S {0} to 90.0N {180} : 2.5 degree)"
      READ (*,*) lat
!       WRITE(*,*) "Enter specific LEVEL ....)"					if there would be some pressure levels with respet to your data 
!       READ (*,*) lev    
 lev=1


 j=0										!hereafter ( j+1) reffers to number of year 

DO  t=1,nt

IF (t == (6+j*12) ) Hjun500(j+1)=h(long,lat,lev,t)		

IF (t == (7+j*12)) Hjul500(j+1)=h(long,lat,lev,t)

IF (t == (8+j*12)) THEN 
Haug500(j+1)=h(long,lat,lev,t)
j=j+1
END IF

ENDDO

end program

 

تصویر moje.am

خداروشکر بلاخره درست شد. مشکل این بود که ما فکر میکردیم باید مثل یک فرمت استاندارد داده‌های چند ترازه خونده بشه. درحالی که این خودش خروجی یک برنامه دیگه بوده و باید در نظر میگرفتیم که نویسنده اون برنامه احتمالا بُعد زمان رو به عنوان بعد سوم در راستای z در نظر گرفته و همه داده‌ها رو در یک رکورد ذخیره کرده. برای همین بود که ما نمیتونستیم بیشتر از یک رکورد رو بخونیم. 1 نکته برنامه نویسی: خوبه زمانی که در یک حلقه قراره داده‌های زیادی خونده بشه، چیزی مثل ضربان قلب برای چک کردن این که حلقه درست کار میکنه و اگر اشتباهه تا کجا پیش رفته، قرار بدیم (مثل خط 17 برنامه ای که اینجا گذاشتم).

مورد بعدی، مسأله جدا کردن یک طول و عرض خاص هست. در جغرافیا طول و عرض از 0 شروع میشه درحالی که در برنامه ما با شماره یک مولفه آرایه‌ها سروکار داریم که از 1 شروع میشن. پس با تقسیم بر 2.5 که در واقع همون تفکیک فضایی داده‌هاست و اضافه کردن عدد 1، میتونیم شماره آرایه متناسب با طول و عرض مورد نظر رو داشته باشیم. اما از اونجایی که ممکنه طول و عرض مورد نظر مضرب صحیحی از 2.5 نباشه این محاسبه منجر به یک عدد اعشاری میشه که برای شماره یک آرایه درست نیست. پس میتونیم با اضافه کردن یک شرط عدد بدست اومده رو به سمت بالا یا به سمت پایین به صورت یک عدد صحیح گرد کنیم.

program testo
        
        INTEGER,PARAMETER :: nx=144, ny=73, y=57, nt=y*12
        INTEGER :: i,j,k,t
        REAL*4,DIMENSION(nx,ny,nt) :: h
        REAL*8,DIMENSION(y):: Hjun500,Hjul500,Haug500			! u dont know about accuracy of data, so you'd better read and write them with low precission but calculate with double precission
        REAL :: lo,la
OPEN(unit=100, file='hgt_500_1948_2005.dat', form='unformatted', status='unknown', access='direct', recl=4*nx*ny*nt)

!-------------------------------------------READING DATA------------------------------------------

        DO t=1,nt
              print*,'nt=',t

                 READ(100,rec=1) h

       write(*,*) t,h(1,1,t)					! this action works as heart of your program and u are able to check the reading process. u can command this line
	ENDDO
!------------------------------------------CHOOSING A PARTICULAR CORDINATE---------

      WRITE(*,*) "Enter specific LONGITUDE (0.0E to 357.5E : 2.5 degree)"
      READ (*,*) lo
      WRITE(*,*) "Enter specific LATITUDE (90.0S {-} to 90.0N {+} : 2.5 degree)"
      READ (*,*) la
	la=la+90							! in order to transfer (- and +) to {0 to 180} 
	
	IF (AMOD(lo,2.5) > 1.25) THEN
	lon=INT(lo/2.5)+1					!rounded to lower
	ELSE
	lon=INT(lo/2.5)+2					!rounded to upper
	END IF
	
	IF (AMOD(la,2.5) > 1.25) THEN
	lat=INT(la/2.5)+1					!rounded to lower
	ELSE
	lat=INT(la/2.5)+2					!rounded to upper
	END IF
 !--------------------------------------------SELECTING SPECIAL MONTHS------------------------
 
 j=0										!hereafter ( j+1) reffers to number of year 

DO  t=1,nt

IF (t == (6+j*12) ) Hjun500(j+1)=h(lon,lat,t)		

IF (t == (7+j*12)) Hjul500(j+1)=h(lon,lat,t)

IF (t == (8+j*12)) THEN 
Haug500(j+1)=h(long,lat,t)
j=j+1
END IF

ENDDO
!---------------------------------------------------------------------------------------------------------------
end program

امیدوارم موفق باشید

تصویر anis

سلام تشکر از اینکه وقتتون رو  روی برنامه گذاشتین

چند سوال برام پیش اومده که ازتون میخواستم بپرسم:

1) به چه شکلی باید متوجه بشیم که فرمت این داده ها و داده های مشابه تو یه رکورد ثبت شده اند؟

2)ایا دستور MOD و AMOD با هم فرقی دارند چون دستور AMOD  رو هرجا نگاه کردم با MOD می اوردند؟

3)چون منطقه کار من نیمکره شمالی است میتوان از نوشتن LA=LA+90 صرفنظر کرد؟

4)دلیل انتخاب 1.25 در (AMOD(la,2.5) > 1.25) رو متوجه نشدم؟

5)هنگام چاپ 3ماه مورد نظر ترتیب ماه مثلا JUN را ابتدا ستون اول بعد باقیمانده به ستون دوم باید بخوانیم یا باید ماه های ژون را سطری بخوانیم؟

باتشکر فراوان

تصویر moje.am

سلام.

جواب سوالها:

1) راهی جز خوندنشون نیست. ما هم فرض رو بر این گذاشتیم که در رکورد ذخیره شدن. و توی خط 16 برنامه قبلی نمایشگری گذاشته بودم که رکوردها رو نشون می‌داد. خوب این شمارنده نشون داد داده‌ها فقط یک رکورد دارن. نتیجه گرفتم ماتریس داده‌ها احتمالا سه بعدی بوده و متغیر زمان بُعد سوم باید باشه (به جای ارتفاع که معمولا بُعد سومه و زمان در رکوردها ثبت میشه)

2)من توی وبسایتی به آدرس زیر دیدم که آرگومانهای ورودی تابع mod از نوع صحیح هستند و amod از نوع حقیقی .پس از این تابع استفاده کردم:

http://gcc.gnu.org/onlinedocs/gfortran/MOD.html

3)خیر. چون شماره آرایه از پایین (یعنی قطب جنوب) شروع میشه و مثلا اگر منظور شما 30 درجه شمالی باشه و فقط همون 30 رو بدون اون محاسبه بزنید، عدد آرایه 60 درجه جنوبی برای شما درنظر گرفته میشه.

4)دقت تفکیک داده‌های شما 2.5 درجه هستند. یعنی به طور مثال اطلاعات 30 و 32.5 درجه رو داره ولی 31 رو نداره.1.25 نصف 2.5 هست. اگر باقیمانده تقسیم که عددی بین 0 تا 2.49 میشه از 1.25 بزرگتر باشه به سمت عرض بالاتر و اگر کمتر از 1.25 باشه به سمت پایین گرد میشه. بنابر این منطق، چنانچه عرض 31 مد نظر شما باشه، عدد مربوط به عرض 30 منظور میشه. البته میشه یک کار بهتر انجام داد و یک میانگین وزن‌دار برای محاسبه مقادیر غیر صحیح (مثلا همون نقطه 31 درجه) نوشت که البته بهتر هم هست.

5) متوجه سوالتون نشدم

تصویر moje.am

راستی شما اگر محاسبه خاصی (مثلا اعمال فیلتر بر داده‌هاتون) ندارید میتونید داده‌ها رو با گردس هم از طریق اسکریپ‌نویسی پردازش کنید. اینطوری به نظر ملموس‌تر هم هست چون میتونید نتیجه رو بلافاصله رسم و مشاهده کنید. در این زمینه میتونید برای کاربست توابع و برنامه‌های آماده گردس، دو وب‌سایت زیر رو بررسی کنید:

http://www.met.wau.nl/education/atd/Practical/scripts/library_local.html

http://www.met.wau.nl/education/atd/Practical/functions/library.html

تصویر anis

سلام به یه مشکلی دوباره برخوردم تو قسمت انتهایی برنامم وقتی دستور WRITE رو میزنم فقط مقدار اولیه رو مثلا ماه جون سال 48 رو محاسبه می کنه بقیه ماه های جون سالهای بعد رو صفر میده برا 2 متغیر دیگه هم به همین شکل

 

ادامه برنامه بعد از خوندن داده ها: 

Hmjun500=0.0

Hmjul500=0.0

Hmaug500=0.0

j=0

Hmjun500=Hmjun500+Hjun500(j+1)

Hmjul500=Hmjul500+Hjul500(j+1)

Hmaug500=Hmaug500+Haug500(j+1)

j=j+1

Hmjun500=Hmjun500/57

Hmjul500=Hmjul500/57

Hmaug500=Hmaug500/57

WRITE(*,*) 'Hmjun',Hmjun500

WRITE(*,*) 'Hmjul',Hmjul500

WRITE(*,*) 'Hmaug',Hmaug500

j=0

Hanumaljun500=0.0

Hanumaljul500=0.0

Hanumalaug500=0.0


Hanumaljun500(j+1)=Hanumaljun500(j+1)+Hmjun500-Hjun500(j+1)

Hanumaljul500(j+1)=Hanumaljul500(j+1)+Hmjul500-Hjul500(j+1)

Hanumalaug500(j+1)=Hanumalaug500(j+1)+Hmjun500-Haug500(j+1)


WRITE(*,*)Hanumaljun500

WRITE(*,*)Hanumaljul500

WRITE(*,*)Hanumalaug500

j=j+1

 

تصویر moje.am

در خوندن داده‌ها هیچ اشکالی وجود نداره. می‌تونید این رو با اضافه کردن یک خط دستور مثل

write(*,*) Haug500(j+1)

در شرط مربوط به جداسازی ماه آگوست چک کنید.

قسمت محاسبه میانگین ماه‌ها رو به صورت زیر اصلاح میکنم (شما فراموش کردید اینا رو در یک حلقه محاسبه کنید، یک سری چیزای زاید رو پاک کردم و حلقه‌ای که ایجاد کردم رو با حروف کوچک نوشتم)

Hmjun500=0.0

Hmjul500=0.0

Hmaug500=0.0

do j=1,y

Hmjun500=Hmjun500+Hjun500(j)

Hmjul500=Hmjul500+Hjul500(j)

Hmaug500=Hmaug500+Haug500(j)
 
 end do



Hmjun500=Hmjun500/57

Hmjul500=Hmjul500/57

Hmaug500=Hmaug500/57

WRITE(*,*) 'Hmjun',Hmjun500

WRITE(*,*) 'Hmjul',Hmjul500

WRITE(*,*) 'Hmaug',Hmaug500

ولی از محاسبات آنومالی نفهمیدم قصد دارید با چه ضابطه‌ای اون رو حساب کنید ولی احتمالا اونم به یک حلقه نیاز داره

برای ارسال دیدگاه وارد شوید یا ثبت نام کنید .