I want to know if there is any intrinsic function which converts date to DDMonYY format in fortran.
As I know Idate returns a date in DDMMYYY.But I would like to know how to get date format in DDMonYY.Do I need to write a separate program which extracts month from Idate and writes character equivalent (like 1 for Jan)
There is the DATE_AND_TIME intrinsic which can return the information you want, with the exception that you get the month as a numeric value in the second element of the VALUES argument. It should then be quite easy to use that month number as the index into a character array with the (3 letter) month names.
Here's a routine that does what you want and a quick program that tests it:
PROGRAM date_test
CHARACTER(len=7) :: date
CALL get_DDMonYY(date)
PRINT*, date
CONTAINS
SUBROUTINE get_DDMonYY(date)
CHARACTER(len=7), INTENT(out) :: date
CHARACTER(len=2) :: dd
CHARACTER(len=3) :: mons(12)
CHARACTER(len=4) :: yyyy
INTEGER :: values(8)
mons = ['Jan','Feb','Mar','Apr','May','Jun',&
'Jul','Aug','Sep','Oct','Nov','Dec']
CALL DATE_AND_TIME(VALUES=values)
WRITE( dd,'(i2)') values(3)
WRITE(yyyy,'(i4)') values(1)
date = dd//mons(values(2))//yyyy(3:4)
END SUBROUTINE get_DDMonYY
END PROGRAM date_test
AFAIK there is no such intrinsic, but it is not at all difficult to write an own subroutine to do that. You Just need to use something as
write(mydate(3:5),fmt='(a3)') 'Jan'
where mydate is the character which will contain DDMonYY.
Related
Suppose I have the matrix c(i,j). I want to write it on the screen on oldest Fortran77 language with three signs after comma. I write
do i=1,N
write(*,"(F8.3)") ( c(i,j), j=1,N )
end do
but the output is in the form
c(1,1)
c(1,2)
...
c(1,10) c(2,1)
c(2,2)
...
Finally, I may simply write
do i=1,N
write(*,*) ( c(i,j), j=1,N )
end do
and then the output is like the matrix, but, of course, it is not formatted.
How to get the correct output in Fortran77?
An edit. It seems that one of solutions is to write
do i=1, N
do j=1, N
write(*,'(F9.3,A,$)') c(i,j), ' '
end do
write(*,*) ' '
end do
Your format only specifies a single float but you actually want to write N per line.
A fairly general solution for this simple case would be something like
program temp
implicit none
integer, parameter :: N=3
real, dimension(N,N) :: c
integer :: i,j
character(len=20) :: exFmt
c = 1.0
write(exFmt,'("(",I0,"(F8.3))")') N
do i=1,N
write(*,exFmt) (c(i,j), j=1,N)
end do
end program
This will make exFmt be '(3(F8.3))', which specifies printing three floats (note you probably really want '(3(F8.3," "))' to explicitly include some spacing).
Note some compilers will allow for exFmt to be just '(*(F8.3))'. This is part of the fortran 2008 specification so may not be provided by all compilers you have access to. See here for a summary of compiler support (see Unlimited format item, thanks to HighPerformanceMark for this)
Finally an easy bodge is to use a format statment like '(1000(F8.3))' where 1000 is larger than you will ever need.
I am a new Fortran user. I am trying to create a file name according to date and time. I only know the command for opening fie which is:
open (unit=10,file='test.txt')
I want to have a file name instead of 'test.txt' using the current date and time when program execute. If anyone can help me I will be grateful then.
You can use date_and_time to achieve this:
module time_ftcs
contains
function timestamp() result(str)
implicit none
character(len=20) :: str
integer :: values(8)
character(len=4) :: year
character(len=2) :: month
character(len=2) :: day, hour, minute, second
character(len=5) :: zone
! Get current time
call date_and_time(VALUES=values, ZONE=zone)
write(year,'(i4.4)') values(1)
write(month,'(i2.2)') values(2)
write(day,'(i2.2)') values(3)
write(hour,'(i2.2)') values(5)
write(minute,'(i2.2)') values(6)
write(second,'(i2.2)') values(7)
str = year//'-'//month//'-'//day//'_'&
//hour//':'//minute//':'//second
end function timestamp
end module
program test
use time_ftcs, only: timestamp
open (unit=10,file='test'//trim(timestamp())//'.txt')
write(10,*) 'Hello World'
close(10)
end program
This results in a file
$cat test2015-04-05_09:32:27.txt
Hello World
You can use the intrinsic subroutine date_and_time to achieve this:
module time_ftcs
contains
function timestamp() result(str)
implicit none
character(len=15) :: str
character(len=8) :: dt
character(len=10) :: tm
! Get current time
call date_and_time(DATE=dt, TIME=tm)
str = dt//'_'//tm(1:6) ! tm(7:10) are milliseconds and decimal point
end function timestamp
end module
program test
use time_ftcs, only: timestamp
open (unit=10,file='test_'//timestamp//'.txt')
write(10,*) 'Hello World'
close(10)
end program
This should result in a file
$cat test_20150405_093227.txt
Hello World
I'm trying to write a time variable from a hydrodynamic model into a netcdf file (unlimited dimension variable). I've attached a simplified code example in Fortran90 that highlights my issue.
The subroutine to write the netcdf file is called multiple times during a simulation depending on a user specified output interval (10 times for this example). I can create the file and add attributes for the first time the subroutine is called.
I can't get the start and count variables correct to write the time variable to the file during the subsequent calls of the subroutine. This is the error, at the writing the model time variable, I receive when trying to compile the code: Error: There is no specific function for the generic 'nf90_put_var'
PROGRAM test_netcdf
IMPLICIT NONE
INTEGER :: N
REAL :: time_step = 2.
! Call efdc_netcdf 10 times
DO N=1,10
CALL efdc_netcdf(N, time_step)
time_step=time_step + 1.
ENDDO
END PROGRAM test_netcdf
************************************
! Create NetCDF file and write variables
SUBROUTINE efdc_netcdf(N, time_step)
USE netcdf
IMPLICIT NONE
LOGICAL,SAVE::FIRST_NETCDF=.FALSE.
CHARACTER (len = *), PARAMETER :: FILE_NAME = "efdc_test.nc"
INTEGER :: ncid, status
INTEGER :: time_dimid
INTEGER :: ts_varid, time_varid
INTEGER :: start(1), count(1)
INTEGER :: deltat
INTEGER :: N
REAL :: time_step
start=(/N/)
count=(/1/)
! Create file and add attributes during first call of efdc_netcdf
IF(.NOT.FIRST_NETCDF)THEN
status=nf90_create(FILE_NAME, NF90_CLOBBER, ncid)
! Define global attributes once
status=nf90_put_att(ncid, NF90_GLOBAL, 'format', 'netCDF-3 64bit offset file')
status=nf90_put_att(ncid, NF90_GLOBAL, 'os', 'Linux')
status=nf90_put_att(ncid, NF90_GLOBAL, 'arch', 'x86_64')
! Define deltat variable
status=nf90_def_var(ncid,'deltat',nf90_int,ts_varid)
! Define model time dimension
status=nf90_def_dim(ncid,'efdc_time',nf90_unlimited,time_dimid)
! Define model time variable
status=nf90_def_var(ncid,'efdc_time',nf90_real,time_dimid,time_varid)
status=nf90_enddef(ncid)
! Put deltat during first call
deltat=7
status=nf90_put_var(ncid, ts_varid, deltat)
FIRST_NETCDF=.TRUE.
ENDIF
! Put model time variable
status=nf90_put_var(ncid, time_varid, time_step, start=start, count=count)
! Close file at end of DO loop
IF(N.EQ.10) THEN
status=nf90_close(ncid)
ENDIF
RETURN
END SUBROUTINE efdc_netcdf
The issue is in the line the compiler flags:
status=nf90_put_var(ncid, time_varid, time_step, start=start, count=count)
You are (correctly) trying to write a scalar variable, time_step, into a specific index (start) along variable time_varid, which is defined on a 1-d, infinite-extent dimension. However, in this case, the optional argument count isn't meaningful; you are writing the scalar, and count can only ever be 1. As a result, the fortran bindings for a nf90_put_var() taking a single scalar for input don't have the optional argument defined for count, and that's why you're getting the "no specific function for the generic' nf90_put_var" error from the compiler. This is all perfectly reasonable, but neither the error message nor the docs are super helpful in figuring out how to solve the problem.
You can fix your code by putting the time_step data into a real, dimension(1) variable, and putting that, instead; but easiest is to just get rid of the count specification, which isn't necessary here anyway:
status=nf90_put_var(ncid, time_varid, time_step, start=start)
Is there a way to call the field of a derived type via string argument in fortran?
something like...
subroutine set(car, fieldName, value)
type(Car_T) :: car
character*(*) :: fieldName
character*(*) :: value
car%[fieldName] = value
end subroutine set
I know you can do stuff like this in javascript, c#, ect., but this could really help me from having a ton of duplicate code if fortran allows it.
No. You will need to write the executable code (perhaps a SELECT CASE construct) that maps the value of the string across to the relevant component.
You only need to write this once for each unique set of component names.
You can do something similar with namelists but it is for items known to the program: not new items.
integer:: inin
real:: rere
namelist /info/ inin, rere
inin = 0 ! default
rere = 20.4 ! default
read (*, nml=info)
print *, 'inin=', inin
print *, 'rere=', rere
stop
end
On the input
&info inin=2 rere=40.0 /
Or if you wish to input one value only
&info rere=3.162 /
i'm a grad student trying to work with atmospheric data files provided by NOAA. I have a code that reads the data but only writes the first four columns of data. I know that the subroutine at the end of the code unpacks the data. I was thinking maybe if I take out the conditional statements then it might write the entire data. But that doesn't work. I need to develop this code so that it writes the entire data file and not just the first four elements. Any help is appreciated. The code is shown below:
PROGRAM CHK_DATA
!-------------------------------------------------------------------------------
! Simple program to dump the first few elements of the data array for each
! record of an ARL packed meteorological file. Used for diagnostic testing.
! Created: 23 Nov 1999 (RRD)
! 14 Dec 2000 (RRD) - fortran90 upgrade
! 18 Oct 2001 (RRD) - expanded grid domain
! 03 Jun 2008 (RRD) - embedded blanks
!-------------------------------------------------------------------------------
REAL, ALLOCATABLE :: RDATA(:,:)
CHARACTER(1), ALLOCATABLE :: CPACK(:)
CHARACTER(4) :: KVAR, MODEL
CHARACTER(50) :: LABEL
CHARACTER(80) :: FDIR, FILE
CHARACTER(3072) :: HEADER
LOGICAL :: FTEST
!-------------------------------------------------------------------------------
INTERFACE
SUBROUTINE UNPACK(CPACK,RDATA,NX,NY,NEXP,VAR1)
CHARACTER(1),INTENT(IN) :: CPACK(:)
REAL, INTENT(OUT) :: RDATA(:,:)
INTEGER, INTENT(IN) :: NX,NY,NEXP
REAL, INTENT(IN) :: VAR1
END SUBROUTINE
END INTERFACE
!-------------------------------------------------------------------------------
! directory and file name
WRITE(*,*)'Enter directory name:'
READ(*,'(a)')FDIR
FDIR=ADJUSTL(FDIR)
WRITE(*,*)'Enter file name:'
READ(*,'(a)')FILE
FILE=ADJUSTL(FILE)
! test for meteo file existence
KLEN=LEN_TRIM(FDIR)
INQUIRE(FILE=FDIR(1:KLEN)//FILE,EXIST=FTEST)
IF(.NOT.FTEST)THEN
WRITE(*,*)'Unable to find file: ',FILE
WRITE(*,*)'On local directory : ',FDIR(1:KLEN)
STOP
END IF
! open file to decode the standard label (50) plus the
! fixed portion (108) of the extended header
OPEN(10,FILE=FDIR(1:KLEN)//FILE,RECL=158,ACCESS='DIRECT',FORM='UNFORMATTED')
! decode the standard portion of the index record
READ(10,REC=1)LABEL,HEADER(1:108)
READ(LABEL,'(5I2,4X,A4)')IYR,IMO,IDA,IHR,IFC,KVAR
WRITE(*,'(A,4I5)')'Opened file : ',IYR,IMO,IDA,IHR
IF(KVAR.NE.'INDX')THEN
WRITE(*,*)'WARNING Old format meteo data grid'
WRITE(*,*)LABEL
WRITE(*,*)HEADER(1:108)
STOP
END IF
! decode extended portion of the header
READ(HEADER(1:108),'(A4,I3,I2,12F7.0,3I3,I2,I4)',ERR=900) &
MODEL, ICX, MN, &
POLE_LAT, POLE_LON, REF_LAT, &
REF_LON, SIZE, ORIENT, &
TANG_LAT, SYNC_XP, SYNC_YP, &
SYNC_LAT, SYNC_LON, DUMMY, &
NX, NY, NZ, &
K_FLAG, LENH
! close file and reopen with proper length
CLOSE (10)
NXY = NX*NY
LEN = NXY+50
OPEN(10,FILE=FDIR(1:KLEN)//FILE,RECL=LEN,ACCESS='DIRECT',FORM='UNFORMATTED')
! print file diagnostic
WRITE(*,'(A,4I5)')'Grid size and lrec: ',NX,NY,NXY,LEN
WRITE(*,'(A,I5)') 'Header record size: ',LENH
! allocate array space
ALLOCATE (RDATA(NX,NY), STAT=KRET)
ALLOCATE (CPACK(NXY), STAT=KRET)
! read entire file and print headers
KREC=1
100 READ(10,REC=KREC,ERR=800)LABEL,(CPACK(K),K=1,NXY)
READ(LABEL,'(6I2,2X,A4,I4,2E14.7)',ERR=900) IY,IM,ID,IH,IF,KL, &
KVAR,NEXP,PREC,VAR1
WRITE(*,'(A)')LABEL
IF(KVAR.NE.'INDX') CALL UNPACK(CPACK,RDATA,NX,NY,NEXP,VAR1)
READ(*,*,END=800)
KREC=KREC+1
GO TO 100
800 STOP
900 WRITE(*,*)'ERROR: decoding header'
WRITE(*,*)LABEL
WRITE(*,*)HEADER(1:108)
END PROGRAM chk_data
!-------------------------------------------------------------------------------
SUBROUTINE UNPACK(CPACK,RDATA,NX,NY,NEXP,VAR1)
CHARACTER(1),INTENT(IN) :: CPACK(:)
REAL, INTENT(OUT) :: RDATA(:,:)
INTEGER, INTENT(IN) :: NX,NY,NEXP
REAL, INTENT(IN) :: VAR1
! only required when dealing with F95 compilers
! replace ICHAR below with internally defined JCHAR function
! CHARACTER MYCHR*1
! JCHAR(MYCHR)=IAND(ICHAR(MYCHR),255)
SCALE=2.0**(7-NEXP)
VOLD=VAR1
INDX=0
DO J=1,NY
DO I=1,NX
INDX=INDX+1
RDATA(I,J)=(ICHAR(CPACK(INDX))-127.)/SCALE+VOLD
VOLD=RDATA(I,J)
IF(I.LE.2.AND.J.LE.2) &
WRITE(*,'(3I5,E12.4)')J,I,ICHAR(CPACK(INDX)),RDATA(I,J)
IF(I.GE.(NX-1).AND.J.GE.(NY-1)) &
WRITE(*,'(3I5,E12.4)')J,I,ICHAR(CPACK(INDX)),RDATA(I,J)
END DO
VOLD=RDATA(1,J)
END DO
END SUBROUTINE unpack
Did you notice the comment
! only required when dealing with F95 compilers
! replace ICHAR below with internally defined JCHAR function
! CHARACTER MYCHR*1
! JCHAR(MYCHR)=IAND(ICHAR(MYCHR),255)
Try to uncomment the definition, and change the calls to CHAR to calls to JCHAR.
ICHAR is an intrinsic function in Fortran that behaves different, than the code expects. It all seems suspicious, because the JCHAR does nothing to numbers below 256.
For further porting consider using IMPLICIT NONE and modules.
---EDIT ---
Now I see your conditionals. If you remove
IF(I.LE.2.AND.J.LE.2) &
and
IF(I.GE.(NX-1).AND.J.GE.(NY-1)) &
what exactly does the code do? We do not have the data.
(I know, there are a lot of the data files on the page you downloaded your program, but I am not going to the all the work for you, sorry.)
Cant you find a complete code to work with the data anywhere?