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...
Related
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
Hej folks, I'm quite the beginner in programming but I read my share of stackoverflow pages, and googled a bit as well, still can't figure if the following is even possible in FORTRAN 90.
I'm trying to isolate the digits in an integer, to point where the hurdle is, consider the following idea :
INTEGER :: n, mult, add
READ *, n ! n = 8
mult = n*2 ! = 16
add = ??? ! where I want to add 1 + 6
Another way, I trust that this will be obvious to anyone reading the code:
INTEGER FUNCTION sum_digits(num)
INTEGER, INTENT(in) :: num
INTEGER, DIMENSION(:), ALLOCATABLE :: digs
INTEGER :: num_digits, ix, rem
num_digits = FLOOR(LOG10(REAL(num))+1)
ALLOCATE(digs(num_digits))
rem = num
DO ix = 1, num_digits
digs(ix) = rem - (rem/10)*10 ! Take advantage of integer division
rem = rem/10
END DO
sum_digits = SUM(digs)
END FUNCTION sum_digits
I've subjected this to a quick series of obvious tests and it has passed all 4 of them. If you find a case for which it doesn't work, fix it. And if you want the array of digits returned, modify the function to return that. If you want it to work for negative integers too throw in ABS() at an appropriate place.
one way to pull off the 'ith' place digit is:
n/10**i-10*(n/10**(i+1))
so for your example:
n-10*(n/10) + n/10-10*(n/100)
It looks like this has been asked many times, but none of the past posts seem to solve my question. All those had to do with matrix/vector while my code does not have any of these, just simple variables. It takes three variables as arguments. It works perfectly fine within the Matlab environment. I only got the error when I compiled it with mcc -m Normal.m and tried to run with the executable like this "./Normal 1 5 0.5". The complete error message is:
Error using /
Matrix dimensions must agree.
Error in Normal (line 4)
MATLAB:dimagree
It is complaining about line 4: N=2/dt, what is wrong with this?
Here is the code:
function val=Normal(l1,l2,dt)
const=(l2/l1-1);
N=2/dt;
S=1.0/sqrt(l2/l1);
Z(1)=S;
for i=2:N
t= -1+(i-1)*dt;
Z(i)=1.0/sqrt(const*t*t+1);
S=S+2*Z(i);
end
Z(21)=1.0/(l2/l1);
S=S+1.0/sqrt(l2/l1);
val=dt*S/2;
end
But dt is not a scalar when passed into the standalone through the command ./Normal 1 5 0.5. It is a character array with 3 elements ('0', '.','5')!
When passing numerical arguments to a standalone, they are passed as strings. Thus, inside the function, you need to convert '0.5' into a double, and similarly for l1 and l2:
dt = str2num(dt);
l1 = str2num(l1);
l2 = str2num(l2);
Note that you can use isdeployed to determine at runtime if the function is a standalone:
if isdeployed, dt = str2num(dt); end
And you might need to display the result:
if isdeployed, disp(val); end
Result:
>> system('Normal 1 5 0.5');
1.4307
>> Normal(1,5,0.5) % .m function for comparison
ans =
1.4307
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.
I wrote the following program in fortran that uses a lapack subroutine called ZGEEV. The idea was to see how the eigenvalues of the matrix change as k goes from real to complex. Analytically, the answers should be 2 and 0, whether k is complex or not. But I obtain a plot that shows a lot variation.
Especially for real k, the plot looks like this -
Here is the code i wrote -
program main
implicit none
!**********************************************
complex(8) :: k,mat(2,2)
complex(8) :: eigenvals(2)
real(8), parameter :: kmax = 2.d0
real(8), parameter :: dk = 1.d-1
real(8) :: kr,ki
!**********************************************
kr=-kmax
do while (kr.le.kmax)
ki= -1.d-3
do while (ki.le.1.d-3)
k=cmplx(kr,ki)
call init_mat(k,mat)
call diagonalize(mat,eigenvals)
print*, real(k), real(eigenvals(2)),aimag(eigenvals(2))
ki=ki+1.d-4
end do
kr=kr+dk
end do
end program main
subroutine init_mat(k,mat)
implicit none
complex(8),intent(in) :: k
complex(8),intent(out):: mat(2,2)
complex(8),parameter :: di=(0.d0,1.d0)
complex(8),parameter :: d1=(1.d0,0.d0)
!**********************************************
mat(1,1) = d1
mat(1,2) = exp(di*k)
mat(2,1) = exp(di*k)
mat(2,2) = d1
return
end subroutine init_mat
subroutine diagonalize(mat,eigenvals)
implicit none
complex(8),intent(in) :: mat(2,2)
complex(8),intent(out):: eigenvals(2)
complex(8) :: vl(2,2),vr(2,2)
complex(8),allocatable:: work(:)
integer(4) :: lwork
complex(8) :: rwork(4)
complex(8) :: mat2(2,2)
integer(4) :: info
!**********************************************
mat2(:,:) = mat(:,:)
allocate(work(6))
call zgeev('N', 'N', 2, mat2, 2, eigenvals, vl, 2, vr, 2, work, -1, rwork, info)
lwork = work(1)
deallocate(work)
allocate(work(lwork))
call zgeev('V', 'V', 2, mat2, 2, eigenvals, vl, 2, vr, 2, work, lwork, rwork, info)
if (info.ne.0) print*, info
stop 'diagonalize failed'
end subroutine diagonalize
Any lazy theorizing as to the causes of this aberration is welcome in the comments!
PS: i wrote up a similar code in python and there the eigenvalues are two constant lines at y=2 and y=0.
in subroutine init_mat(k,mat)
mat(1,2) = exp(di*k)
and
mat(2,1) = exp(di*k)
But one of them, e.g., mat(2,1) should = exp(-di*k)
Although your math project calls for a matrix with e^ik and e^-ik on the off-diagonals, the code shown instead is creating a matrix with e^ik on both off-diagonals. The matrix actually coded has complex eigenvalues, so the subroutines for finding eigenvalues may be working correctly and the input as shown has a mis-specification.
So what are the eigenvalues of [[1, e^ik], [e^ik, 1]]?
Well, the trace is still 2, so the eigenvalues sum to 2.
And the determinant is 1-e^(2ik), so the product is complex.
This suggests that the eigenvalues of the matrix actually input are complex conjugates that sum to 2. By inspection, the eigenvalues seem to be 1 +/- e^ik