I am trying to write a program that would simply read a table defining a dependency of a coefficient on temperature (table of 2 columns, 27 lines) and that would use the data in an equation. The rest of the variables defined in the subroutine are provided by a FEM program (t(1) and timinc).
My program seems to loop through the whole table, but I have a suspicion that it reads the last row of the table 27 times. Please can someone explain to me the problem?
subroutine mycode(eqcpnc,t,timinc)
#ifdef _IMPLICITNONE
implicit none
#else
implicit logical (a-z)
#endif
real*8 a, dtdl, eqcpnc, t, timinc
integer iostat, ios, n
dimension t(1), dtdl(1)
c
open (1, file='Coefficient.txt', iostat=ios)
n=0
do
read(1, *, iostat=ios) dtdl(1), a
if (ios/=0) exit
n=n+1
enddo
rewind(1, iostat=ios)
c
eqcpnc=t(1)*a**timinc
c
close(1)
return
end
The original table 'Coefficient.txt' looks like this:
27.85 5.22E-19
77.85 1.47E-18
127.85 4.17E-18
177.85 1.19E-17
227.85 3.44E-17
277.85 1.02E-16
327.85 3.23E-16
377.85 1.12E-15
427.85 4.50E-15
477.85 2.23E-14
527.85 1.42E-13
577.85 1.16E-12
627.85 1.20E-11
677.85 1.44E-10
727.85 1.69E-09
777.85 1.85E-08
827.85 2.31E-07
877.85 5.69E-07
927.85 1.34E-06
977.85 3.04E-06
1027.85 6.64E-06
1077.85 1.40E-05
1127.85 2.84E-05
1177.85 5.61E-05
1227.85 1.08E-04
1277.85 2.01E-04
1327.85 3.65E-04
I need help turning a Decay.txt file into an array, the first 1-3 and 5th columns are numbers, the third column is "time elapsed" in integers, but the 4th column is a unit of time (milliseconds, Months, Days) but its spelled out with characters. i cant get this mixed array (numbers and characters) to transfer over to matlab
ideally id like to take the unit of time (4th column) change it to a seconds value, (i.e. hour becomes 3600 seconds) then multiply it by the number in the third column and have a final 4 column array where the 3rd column is simply the time elapsed in seconds
anyone know how to do either of these things?
ive tried
Decay = fopen('Decay.txt','r');
B = fscanf(Decay,'%f',[5 inf]);
which stops and has an error as soon as it hits the 4th column
and
Decay = fopen('Decay.txt','r');
B = fscanf(Decay,'%s',[5 inf]);
but this just creates a 5x10000 column where every single number, decimal, and letter is on its own in its own cell of the array
Your first example
Decay = fopen('Decay.txt','r');
B = fscanf(Decay,'%f',[5 inf]);
Breaks because it can't scan the fourth column (a string) as a number (%f). Your second example doesn't have numbers because you're scanning everything as a string (%s).
The correct specifier for your format should be
'%f %f %f %s %f'
However, if you call fscanfwith it, as per documentation:
If formatSpec contains a combination of numeric and character specifiers, then A is numeric, of class double, and fscanf converts each text characters to its numeric equivalent. This occurs even when formatSpec explicitly skips all numeric fields (for example, formatSpec is '%*d %s').
So this input file:
50 1.2 99 s 0
6.42 1.2 3.11 min 1
22 37 0.01 h 2
Has this (undesired) output:
>> fscanf(Decay, "%f %f %f %s %f", [5, inf])
ans =
50.0000 6.4200 110.0000 104.0000
1.2000 1.2000 1.0000 2.0000
99.0000 3.1100 22.0000 0
115.0000 109.0000 37.0000 0
0 105.0000 0.0100 0
That happens because a matrix in MATLAB can't have multiple data of different types. So, your best bet is scanning into a cell array, which can have any type inside.
B = textscan(Decay, "%f %f %f %s %f")
Returns a cell array with the appropriate types. You can use this output to convert the time data into the same unit and build your vectors/matrix. Columns 1, 2, 3 and 5 are trivial to do, just by accessing the cell B{n} for each n.
Column 4 is a cell array of cells. In each internal cell, there's the string you have. You need to apply a conversion from string to the number you need. For my example, such function would look like:
function scale = DecayScale(unit)
switch(unit)
case 's'
scale = 1;
case 'min'
scale = 60;
case 'h'
scale = 3600;
otherwise
throw('Number format not recognized');
end
end
Which you could then apply to the 4th column like:
timeScale = cellfun(#DecayScale, B{4})
And get the final time as:
timeColumn = B{3} .* timeScale
UPDATED - I added 2 screen shots with 0.00 in the data and one with 1234.56 in the data
I am using an old VB6 set of code as 95% works to read a text file that gets converted and stored in MS SQL. The strings are all good however there are numbers mixed into the text binary file that I haven't figured out how to read. The original application the numbers are all currency however the hex dump of the numbers looks to be 4 byte numbers.
Either way I am not sure how to read the numbers into a local variable. Maybe I am not starting at the correct place in the data. In the example below I am starting at the <160>.
Here is a dump of the part of the binary file with 0.00 in the data:
Here is a dump of the part of the binary file with 1234.56 in the data:
Note the arrow point to where the data changed.
This is my last try but that doesnt work either.
Function ReadFloat(f As Integer, Optional ShowDB As Boolean = False) As String
On Error GoTo 0
Dim c As Single
Dim S(4) As Byte
Dim x As Integer
Dim flt As Single
Get f, , S
For x = 1 To 4
Debug.Print x & " " & S(x) & " " & Hex(S(x)); "='" & Chr(S(x)) & "'"
Next x
CopyMemory flt, S, 4
My initial inspection suggests that the bytes starting:
40 E2 01
are what you're looking for. These are stored little endian, so 01E240 is hex for 123456 in decimal. So my guess would be 32 bit integers (4 byte long type). You can test this by using -0.01 as a value, this should give:
... FF FF FF FF ...
in the file.
If you're only interested in reading just these values then you can read and discard the first x values. Something like:
Dim yDiscard(123) As Byte
...
Get #1, ,yDiscard
Or alternatively, just seek to the position first before reading:
Seek #1, 123
To work out what byte values to expect in general, I found the following to be useful. Just run the code in a module:
Sub main()
Dim lValue As Long
Dim cValue As Currency
Dim nValue As Single
Dim dValue As Double
Dim sValue As String
Dim vValue As Variant
lValue = 123456
cValue = 1234.56
nValue = 1234.56
dValue = 1234.56
sValue = "1234.56"
vValue = CDec(1234.56)
Open "c:\test1.bin" For Binary As 1
Open "c:\test2.bin" For Binary As 2
Open "c:\test3.bin" For Binary As 3
Open "c:\test4.bin" For Binary As 4
Open "c:\test5.bin" For Binary As 5
Open "c:\test6.bin" For Binary As 6
Put #1, , lValue
Put #2, , cValue
Put #3, , nValue
Put #4, , dValue
Put #5, , sValue
Put #6, , vValue
Close #1
Close #2
Close #3
Close #4
Close #5
Close #6
End Sub
You can then inspect each file in a hex editor (I use MadEdit but anything will do).
It's probably useful to also try simple values like 1.00, 2.00, 10.00, -1.00 and see how the bytes differ each time.
This may also be informative (fairly in depth):
http://www.codeguru.com/vb/gen/vb_misc/algorithms/article.php/c7495/How-Visual-Basic-6-Stores-Data.htm
And to actually answer the question, something like the following will read a 32 bit integer and convert to currency:
Function ReadAmount(iFileHandle As Integer, lFileBytePosition As Long) As Currency
Dim lValue As Long
Seek #iFileHandle, lFileBytePosition
Get #iFileHandle, , lValue
ReadAmount = CCur(lValue) / 100
End Function
There's no need for an intermediate byte array.
True floating point are bad when using currency, so actually your number is an integer with fixed point.
First : put them in an integer variable (type Long)
Second : divide by 100 to get back the decimal !
Straightforward method to convert it to single:
Dim S(4) As Byte 'your 4 bytes, like (1)=&H40, (2)=&HE2 (3)=&H01, (4)=&H00
Dim Buffer As Long
Buffer = S(4) * 16777116 Or S(3) * 65536 Or S(2) * 256 Or S(1)
Dim flt As Single
flt = Buffer / 100
AM writing a code in FORTRAN to read a mesh file in STARCD format(has.cel, .vrt and .bnd) am trying to use a counter and a pointer array, to count the number of vertices and the cells the file has so that it would be easy to define the neighbours of the cells later. Can you please take a look at the code and correct me out please and i get an error Invalid form of array reference at (1).
ivrt(icell(i)%cell(2)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
1
The error is shown here for all the lines with the icounter. To give u the outline of what is being done, i have just declared the types i have used and the variables, am reading the three files .vrt(nov) .cel(noc) and .bnd(bnd) and defining the datastructure where .vrt has 4 columns, .cel has 5 columns.
program reader
implicit none
type::node
real,allocatable,dimension(:)::point1,icounter,vrt
end type
type::elemtype
integer,allocatable,dimension(:)::quad,refback
integer,allocatable,dimension(:)::tri
end type
type::cel
integer,allocatable,dimension(:)::cell,ishape,reffwd
end type
type::boundnode
integer,allocatable,dimension(:)::bnode
end type
type::boundarycell
integer,allocatable,dimension(:)::bcell
end type
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
type(node),allocatable,dimension(:)::ivrt
type(elemtype),allocatable,dimension(:)::iquad
type(elemtype),allocatable,dimension(:)::itri
type(cel),allocatable,dimension(:)::icell
type(boundnode),allocatable,dimension(:)::ibnode
type(boundarycell),allocatable,dimension(:)::ibcell
integer::nov,noc,bnd,nbnd,i,j,k,count1,count2,numquad,flag,numtri
integer::usercell,tcell,cindex
integer::celltype,n,m
integer,allocatable,dimension(:,:)::qedg1,qedg2,qedg3,qedg4
integer,allocatable,dimension(:,:)::tedg1,tedg2,tedg3,tedg4
integer,allocatable,dimension(:)::ctype
integer,allocatable,dimension(:)::quadvert
integer,allocatable,dimension(:)::trivert
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
CALL SYSTEM("wc STAR.vrt > NO_V")
OPEN (UNIT=10,FILE='NO_V',STATUS="OLD",ACTION="READ")
READ (10,"(i6)")nov
close(10)
print *, nov
CALL SYSTEM("wc STAR.cel > NO_C")
OPEN (UNIT=10,FILE='NO_C',STATUS="OLD",ACTION="READ")
READ (10,"(i6)")noc
close(10)
print *, noc
CALL SYSTEM("wc STAR.bnd > NO_B")
OPEN (UNIT=10,FILE='NO_B',STATUS="OLD",ACTION="READ")
READ (10,"(i6)")nbnd
close(10)
print *, nbnd
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
allocate(ivrt(nov))
do i=1,nov
allocate(ivrt(i)%vrt(1:4))
allocate(ivrt(i)%icounter(1))
end do
allocate(icell(noc))
do i=1,noc
allocate(ivrt(i)%icounter(1))
allocate(icell(i)%cell(1:5))
allocate(icell(i)%ishape(1))
allocate(icell(i)%reffwd(1))
end do
allocate(ibnode(nbnd))
do i=1,bnd
allocate(ibnode(i)%bnode(1:3))
end do
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
open(unit=10,file="STAR.vrt",status="old",action="read")
do i = 1,nov
read(10,*)ivrt(i)%vrt(1), ivrt(i)%vrt(2), ivrt(i)%vrt(3), ivrt(i)%vrt(4)
!print *, ivrt(i)%vrt(1), ivrt(i)%vrt(2), ivrt(i)%vrt(3), ivrt(i)%vrt(4)
end do
close (10)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
open(unit=10,file="STAR.cel",status="old",action="read")
do i=1,noc
read(10,*)icell(i)%cell(1),icell(i)%cell(2),icell(i)%cell(3),icell(i)%cell(4),icell(i)%cell(5)
ivrt(icell(i)%cell(2)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(3)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(4)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
if (icell(i)%cell(4).ne.icell(i)%cell(5))then
ivrt(icell(i)%cell(5)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
end if
end do
close(10)
do i=1,nov
allocate(ivrt(i)%point1(ivrt(i)%icounter(1)))
end do
ivrt(:)%icounter(:)=0
open(unit=10,file="STAR.cel",status="old",action="read")
do i=1,noc
read(10,*)icell(i)%cell(1),icell(i)%cell(2),icell(i)%cell(3),icell(i)%cell(4),icell(i)%cell(5)
ivrt(icell(i)%cell(2)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(3)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(4)%icounter(1)=ivrt(icell(i)%cell(2)%icounter(1)+1
ivrt(icell(i)%cell(2))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
ivrt(icell(i)%cell(3))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
ivrt(icell(i)%cell(4))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
if (icell(i)%cell(4).ne.icell(i)%cell(5))then
ivrt(icell(i)%cell(5))%point1(ivrt(icell(i)%cell(2))%icounter(1))=i
ivrt(icell(i)%cell(5))%icounter(1)=ivrt(icell(i)%cell(2))%icounter(1)+1
end if
end do
close(10)
There are two brackets missing... Do you mean:
ivrt( icell(i)%cell(2)%icounter(1) ) = ivrt( icell(i)%cell(2)%icounter(1)+1 )
^ ^
or:
ivrt( icell(i)%cell(2)%icounter(1) ) = ivrt( icell(i)%cell(2)%icounter(1) ) + 1
^ ^
That error is repeated several times throughout your code!
Like Alexander Vogt I agree that there are brackets missing. However, there is another problem.
In the defintion of the type cel the component cell is an integer array:
type :: cel
integer, allocatable, dimension(:) :: cell, ishape, reffwd
end type
type(cel), allocatable, dimension(:) :: icell
so one cannot have a reference icell(i)%cell(2)%...
Perhaps, then, the declaration of cel should be
type :: cel
type(node), allocatable, dimension(:) :: cell
! Also components ishape, reffwd of some type.
end type
end type
And then the bracket corrections additionally.
I've an integer array
int(4) :: idate ! 1979 March 1st 00hrs
write(*,*)idate ! prints ' 0 3 1 1979'
I want idate to be saved in a different variable (integer/integer array only) which will print the date as:
1979030100
without changing it into char/strings.
Can this be done. Pardon me if it is trivial but I've spent quite a bit of my time on it.
You could do something like this:
integer :: date_as_int
...
date_as_int = idate(1)*10**6 + idate(2)*10**4 + idate(3)*10**2 + idate(4)
You might even get away with
date_as_int = sum(idate*10**[6,4,2,0])
or
date_as_int = dot_product(idate, 10**[6,4,2,0])
The square brackets syntax is from Fortran 2003. With older compilers [6,4,2,0] should be replaced by (/6,4,2,0/).