How to read binary file written by Matlab in Fortran? - matlab

I want to read an array of double precision values written in a binary file by Matlab into a code in Fortran (compiler gfortran), however my code to read it is not working. Can you please show me the correct way to do it?
Here is my Matlab code, which works.
a=[0.6557 0.0357 0.8491 0.9340 0.6787];
fid=fopen('ft1.bin','w');
fwrite(fid,a,'double');
fclose('all');
fid=fopen('ft1.bin','r');
a2=fread(fid,5,'double');
fclose('all');
a2
Here is my Fortran, code which returns an error when I try to read file ft1.bin
program code1
implicit none
double precision, dimension(5) :: a2
integer :: i
open(1,FILE="ft1.bin",FORM='UNFORMATTED',ACTION='READ')
read(1) a2
close(1)
print *, a2
end program code1
When I try to run it,
gfortran code1.f90 -o bb1
./bb1
At line 8 of file code1.f90 (unit = 1, file = 'ft1.bin')
Fortran runtime error: Unformatted file structure has been corrupted

One has to avoid the record based I/O with ACCESS="STREAM", e.g.,
PROGRAM test
IMPLICIT NONE
INTEGER, PARAMETER :: dp = KIND(1D0)
INTEGER :: funit, io_stat
REAL(dp) :: a(5)
OPEN(NEWUNIT = funit, FILE = 'ft1.bin', STATUS = "OLD", ACCESS = "STREAM", FORM = "UNFORMATTED", IOSTAT = io_stat)
READ(funit, IOSTAT = io_stat) a
WRITE(*, *) a
CLOSE(funit)
END PROGRAM

Related

Calling a Matlab function in Fortran

Using the MATLAB Engine API for Fortran, I am trying to call a simple MATLABfunction from a Fortran code.
I followed the fengdemo example found here.
It worked, so I want to adapt my Fortran code to call a specific Matlab script I wrote.
My MATLAB script call_fortran.m is very simple: it takes x as an entry and multiplies it by 2:
function multiply = call_fortran(x)
multiply = 2*x;
end
I want my FORTRAN code to generate a variable my_x, open a MATLAB session, send the variable to the workspace, apply the function call_fortran and display the result. Using the fengdemo.f code, I wrote :
program main
C Declarations
implicit none
mwPointer engOpen, engGetVariable, mxCreateDoubleMatrix
mwPointer mxGetPr
mwPointer ep, my_x ! ep: variable linked to engOpen, starting a Matlab session, my_x: variable que je veux donner a Matlab
double precision my_x
integer engPutVariable, engEvalString, engClose
integer temp, status
mwSize i
my_x = 6
ep = engOpen('matlab ')
if (ep .eq. 0) then
write(6,*) 'Can''t start MATLAB engine'
stop
endif
C Place the variable my_x into the MATLAB workspace
status = engPutVariable(ep, 'my_x', my_x)
C
if (status .ne. 0) then
write(6,*) 'engPutVariable failed'
stop
endif
! My issue now is to call the correct Matlab script
! nlhs = 1
! plhs = 1
! nrhs = 1
! prhs = 1
! integer*4 mexCallMATLAB(nlhs, plhs, nrhs, prhs, functionName)
So I have my my_x, I send it to MATLAB, but how do I apply the call_fortran.m function and get the new value of my_x?
You have two fundamental errors with this code. You do not use the correct variable type for my_x, and you cannot call mexCallMATLAB( ) from an Engine application (that can only be used in mex routines). Let's fix these.
First, the my_x variable needs to be an mxArray, not a double precision variable. There are various ways to do this, but for a scalar, the easiest way to create this array is as follows:
mwPointer, external :: mxCreateDoubleScalar
mwPointer my_x
my_x = mxCreateDoubleScalar(6.d0)
Then you can pass this to the MATLAB Engine per your current code. To call your function in the MATLAB Engine workspace, you need to evaluate a string there:
integer*4, external :: engEvalString
integer*4 status
status = engEvalString( ep, 'result = call_fortran(my_x)' )
The result should display in the Engine workspace since we did not terminate the string with a semi-colon. If you want to get the result back into your Fortran code, you would need to do something like this:
mwPointer, external :: engGetVariable
mwPointer result
result = engGetVariable( ep, 'result' )
The result inside your Fortran code will be an mxArray. To extract the number there are various ways, but for a scalar it would be easiest to just do as follows (the real*8 is used instead of double precision to match the MATLAB API signature in the doc exactly):
real*8, external :: mxGetScalar
real*8 myresult
myresult = mxGetScalar(result)
To avoid memory leaks, once you are done with the mxArray variables you should destroy them. E.g.,
call mxDestroyArray(my_x)
call mxDestroyArray(result)
Having written all this, are you sure you want to create MATLAB Engine applications, and not mex routines? Mex routines are generally easier to work with and don't involve extra data copies to pass variables back & forth.

How to write MATLAB variable into text file with format like 3.4d3

I want to read MATLAB output by Fortran code.
Therefore, I need to write MATLAB script to generate a text file with decimal notation.
like: MATLAB code
x=123.45
fprintf(filetxt,'%f',x)
Output:
123.45
How to write output command or set format so I get this value in filetxt like:
1.2345d02
Maximum I can get is 1.2345e02 but I want to write like 1.2345d02
As suggested by #francescalus, I think your Fortran compiler will probably read in a floating-point literal like 1.2345e02 as expected into a double-precision variable (as in the code below). So, I guess you can just write 1.2345e02 rather than 1.2345d02 to a data file...
program main
implicit none
real :: xs
double precision :: xd
open(10, file='test.dat', status='old')
read(10,*) xs
read(10,*) xd
close(10)
print "(a, e30.18)", "xs = ", xs
print "(a, e30.18)", "xd = ", xd
end
test.dat:
0.1234567890123456e12
0.1234567890123456e12
Result (gfortran test.f90):
xs = 0.123456790528000000E+12
xd = 0.123456789012345596E+12 <-- double-precision accuracy

Matlab from Fortran - problems transferring big matrix

I have to call Matlab from Fortran and execute a program there. I have a large 3xN (N is around 2500) matrix of data, which needs to be transferred to Matlab. I noticed some discrepancies in the data - the last line of the Fortran matrix becomes first line in Matlab (other lines stay however on their place, shifted down by 1), and this line also looses the first value.
Like this - In Fortran
1.1 1.2 1.3
2.1 2.2 2.3
.....
1999.1 1999.2 1999.3
2000.1 2000.2 2000.3
becomes in Matlab
0.0 2000.2 2000.3
1.1 1.2 1.3
2.1 2.2 2.3
.....
1999.1 1999.2 1999.3
I cant understand what is going wrong somehow.. Spent several hours...
node_xyz_ini = mxCreateDoubleMatrix(M, N, 0) ! M, N - dimensions
call mxCopyReal8ToPtr(CoordSet, mxGetPr(node_xyz_ini), M*N)
I use Octave rather than matlab. With that as a caveat, here is an example of what I use, this for double precision twod arrays:
MODULE IO
use, intrinsic :: iso_c_binding
!! use c_float,c_double, c_double_complex, c_int,c_ptr
implicit none
real (c_double), allocatable :: x(:,:),h(:),f(:)
integer (c_int),allocatable :: t(:,:)
integer (c_int) :: nx,ne
contains
Subroutine Write_Array_RDP(varname,variable)
implicit none
integer (c_int) :: kx,ky,sh(2),ncol,nrow
character(len=7),intent(in) :: varname
character(:),allocatable :: wrtfmt
character(range(ncol)) :: res
real(c_double),intent(in) :: variable(:,:)
open(unit=10,file=varname,form="formatted",status="replace",action="write")
write(10,fmt="(A)")"# created by ?? "
sh=shape(variable)
ncol=sh(2);nrow=sh(1)
write(10,fmt="(A,A)")"# name: ",varname
write(10,fmt="(A)")"# type: matrix"
write(10,fmt="(A,i0)")"# rows: ",nrow
write(10,fmt="(A,i0)")"# columns: ",ncol
write(res,'(i0)') ncol
wrtfmt="("//trim(res)//"(e20.12))"
do ky=1,nrow
write(10,fmt=wrtfmt)(variable(ky,kx),kx=1,ncol)
end do
write(10,*)" "
write(10,*)" "
close(10)
End Subroutine Write_Array_RDP
END MODULE IO
Program Main
use IO
implicit none
real (c_double),allocatable :: DPArray(:,:)
allocate(DPArray(3,3))
DPArray=reshape((/1.0d0,2.0d0,3.0d0,1.0d0,2.0d0,3.0d0,1.0d0,2.0d0,3.0d0/),(/3,3/))
Call Write_Array_RDP('DPArray',DPArray)
End Program Main
I compile and link with 'gfortran name.f90' then run with ./a.out. The file DPArray has been created. Then in Octave :
load DPArray
DPArray
produces the output:
1 1 1
2 2 2
3 3 3
I have found it necessary to recode the Write subroutine for different variable types (Write_Array_CMPLX, Write_Array_INT) etc...

Calculating a checksum of a real array in Fortran

I have a large array in Fortran:
real, dimension(N) :: arr
And I need to check if the array is exactly the same in different runtimes of the program. To do this, I wanted to create a checksum of the array to compare. However, I don't know which algorithm to implement. I have looked at Flether's and Adler's algorithm, but have trouble reading the C syntax provided in the examples I found. And also, I don't know how to implement them with Reals instead of chars/integers.
In the C implementations I have found they return:
return (b << 16) | a;
But I don't know how to implement the b << 16 part in Fortran, or if this translates well to reals.
I finally solved the issue by implementing Adler-32 in Fortran:
subroutine test_hash(var)
implicit none
real, dimension(N), intent(in) :: var
integer, dimension(N) :: int_var
integer :: a=1, b=0, i=1, mod_adler=65521, hash = 0
int_var = TRANSFER(var, a, nijk)
do i= 1, NIJK
a = MOD(a + int_var(i), mod_adler)
b = MOD(b+a, mod_adler)
end do
hash = ior(b * 65536, a)
print*, hash
end subroutine test_hash
I ended up using the Fortran intrinsic Transfer function to convert the 32bit reals to 32bit integers, since that's what the algorithm relies on. After this I perform the standard loop. Use the IOR function as suggested by #VladimirF and represented the b<<16 as b * 65536 described by #ja72.
Finally I'll be able to print the hash to the console.
The reason for implementing it this way was because it's faster in use than opening a file, computing the checksum per file. The main reason for this is because there are many variables I need to check which switch often since I'm only using this for debugging purposes.
A modified version of Lars accomplishes the same without a large temporary array. Also, in Fortran, initializing the variable at declaration time implies the "save" attribute, which is not desirable in this case.
function hash_real_asz(var,size_var) result(hash)
implicit none
integer(8) :: hash
real(8), dimension(*), intent(in) :: var
integer, intent(in) :: size_var
integer(4) :: a,b,i,j
integer(4), parameter :: mod_adler = 65521
integer(4), allocatable :: tmp(:)
a = 1
b = 0
do i= 1, size_var
tmp = transfer(var(i), [0]) ! tmp will be an integer array sufficient to hold var(i)
do j = 1,size(tmp)
a = MOD(a+tmp(j), mod_adler)
b = MOD(b+a, mod_adler)
end do
end do
hash = ior(b * 65536, a)
end function

How to return a value from a Python callback in Fortran using F2Py

Consider the following Fortran subroutine, defined in test.f:
subroutine test(py_func)
use iso_fortran_env, only stdout => output_unit
external py_func
integer :: a
integer :: b
a = 12
write(stdout, *) a
b = py_func(a)
write(stdout, *) b
end subroutine
Also the following Python code, defined in call_test.py:
import test
def func(x):
return x * 2
test.test(func)
Compiled with the following (Intel compiler):
python f2py.py -c test.f --fcompiler=intelvem -m test
I expect this as output when I run test:
12
24
But I actually get this:
12
0
It seems as if b is being initialised with a default value instead of the result of test. I have tried using the following in the Fortran:
!f2py intent(callback) py_func
external py_func
!f2py integer y,x
!f2py y = py_func(x)
But my program crashes after the printout of 12 to the console.
Any ideas what could be going on here? The reason for the crash would be a bonus, but I'm really just interested in getting a simple callback working at this point.
I don't claim to understand it, I found the answer on an F2Py forum thread. Adding integer py_func (not prefixed by !f2py) does the trick for me:
subroutine test(py_func)
use iso_fortran_env, only stdout => output_unit
!f2py intent(callback) py_func
external py_func
integer py_func
!f2py integer y,x
!f2py y = py_func(x)
integer :: a
integer :: b
a = 12
write(stdout, *) a
b = py_func(a)
write(stdout, *) b
end subroutine
Perhaps this is to do with space being needed for a temporary value used to store the result before being assigned to b? In any case, it is apparently compiler-dependent, which explains why it is not in various F2Py callback examples you can find elsewhere online.