How to convert 1D matlab array code into Fortran code and to get the values - matlab

I want to convert this Matlab code into Fortran code. I have provided the codes here for both Matlab and Fortran. The parameters are also given here.
Matlab code
L_10 = 1.0e-10;
e = 0.4;
n = 100000;
R = 3.1e+5;
K0_10 = 1.0e-10;
Ci = 1.0e-15;
zv = 1.2;
Dv = 1
Rho = 2.0e-4
dt = 0.01
for i=1:n
L_10(i+1) = L_10(i) + dt*(e*K0_10- R*L_10(i)*Ci- zv*Dv*L_10(i)*Rho);
end
I have written the following Fortran code but it does not work
real, dimension (:), allocatable:: L_10
real, parameter :: e = 0.4
integer, parameter :: n = 100000
real, parameter :: R = 3.1e+5
real, parameter :: K0_10 = 1.0e-10
real, parameter :: Ci = 1.0e-15
real, parameter :: zv = 1.2
real, parameter :: Dv = 1.0
real, parameter :: Rho = 2.0e-4
real, parameter :: dt = 0.01
integer:: i
do i=1:n
L_10(i+1) = L_10(i) + dt*(e*K0_10- R*L_10(i)*Ci- zv*Dv*L_10(i)*Rho);
end
How to initialize the array value in the Fortran code? How the iteration will work in Fortran? It works perfectly well in Matlab.

This program in Fortran is producing the same output as in Matlab. The iteration of array is different in do loop in Fortran as shown below. The iteration is saved in Fortran without indexing but in Matlab, it is done with indexed as shown in Matlab code.
program oneDimention
implicit none
integer, parameter :: n = 10
real, dimension (n):: L_10
real, parameter :: e = 0.4
real, parameter :: R = 3.1e+5
real, parameter :: K0_10 = 1.0e-10
real, parameter :: Ci = 1.0e-15
real, parameter :: zv = 1.2
real, parameter :: Dv = 1.0
real, parameter :: Rho = 2.0e-4
real, parameter :: dt = 0.01
integer:: i
L_10 = 1.0e-10
do i=1,n
L_10 = L_10(i) + dt*(e*K0_10- R*L_10(i)*Ci- zv*Dv*L_10(i)*Rho);
print*,L_10(i)
end do
end program oneDimention

I can immediately see two problems with the Fortran. You've chosen to make L_10 allocatable, but the code doesn't allocate it. You could either make it static, by changing its declaration to
real, dimension (n+1) :: L_10
If you choose this approach you'll have to move the declaration until after the declaration of n itself, the compiler won't work with forward declarations. The alternative would be to leave the declaration as it is but to insert the statement
allocate(L_10(n+1))
after the declarations but before you try to make first use of the array. Review your documentation for the allocate statement and learn how to get a status code reported in case things go awry.
You can then set the value of all elements in the same way you do in Matlab,
L_10 = 1.0e-10
You have the syntax for the do statement wrong, it should start with the line
do i = 1, n
with a comma where Matlab uses the colon.
There may be other problems in the Fortran which I haven't spotted, but your compiler will help you there.

Related

How to solve a matlab fit?

So I want to solve a plot fit for several points, but the problem, that I am facing right now is, that my fit object fit_eq is a char but solve needs a sym. I searched everywhere and couldn't find a solution how to fix this. Here is my code, I cut unimportant parts, and some variables are german words, so don't get confused. gesamt is a 60x20 matrix, where every odd column is the same (it's made out of 10 matrices which are an outcome of a meassurement).
anzahlproben = 10;
for i = 1:2:anzahlproben*2
probe = gesamt(:,i:i+1);
[row c]=find(probe==0);
row(1:2,:)=[];
for j=row
probe(j,:)=[];
end
N22_{(i+1)/2} = probe;
end
for i = 1:1:anzahlproben
x = N22_{i}(1:1:size(N22_{i},1),1);
y = N22_{i}(1:1:size(N22_{i},1),2);
ft = fittype('poly9');
fitobject_{i}=fit(x,y,ft);
end
cvalues = coeffvalues(fitobject_{1});
cnames = coeffnames(fitobject_{1});
fit_eq = formula(fitobject_{1});
for ii=1:1:numel(cvalues)
cname = cnames{ii};
cvalue = num2str(cvalues(ii));
fit_eq = strrep(fit_eq, cname , cvalue);
end
y=1;
syms x
erg = (solve(fit_eq == y,x))
I got the last part from here and gives an equation in a char.
Matlab gives the output:
erg =
Empty sym: 0-by-1
Which can't be right. Any ideas?
As mentioned in the first line of the doc:
Support for character vector or string inputs has been removed.
Instead, use syms to declare variables and replace inputs such as
solve('2*x == 1','x') with solve(2*x == 1,x).
So eqn should be of class sym not a string!
Try:
erg = solve(str2sym(fit_eq) == y,x)
If it still don't work either your equation is wrong or you've not declared the symbolic variables involved in your equation.

Integrate function in MATLAB

I am new to Matlab. I would like to integrate a function. I try int() and integrate() but they all cause problems to me - not enough parameters or other different errors, I have tried many combinations with documentation. My current code is the following, I would like to be able to pass numbers p and q to res and obtain a numerical result:
syms x;
w = 1;
hbar = 1.054571800*10^(-34);
k = (w/(pi*hbar))^(1/4);
e = #(q) (w*q/hbar)^(1/2);
waveF = #(q) k*exp(-feval(e,q)*feval(e,q)*1/2.0)*1.0/1;
func = #(p,q) waveF(q-x/2)*waveF(q+x/2)*exp(1i*p*x/(hbar));
res = #(p,q) int(func(p,q), x = -Inf..Inf);
Currently " x = " is indicated as en error although it seems ok according to the documentation.
Thanks.
You are using anonymous functions in concert with the Symbolic Toolbox and have mistakenly used the MuPAD version of int, which is actually generating the error, when you wanted the Symbolic int.
While mixing anonymous functions with Symbolic calls is not illegal, I think you would be better served by sticking to one paradigm of computation at a time:
Purely Symbolic version using Symbolic functions:
syms x p q e(q) waveF(q) func(p,q) res(p,q);
w = sym(1);
hbar = sym('1.054571800E-34');
k = (w/(pi*hbar))^(1/4);
e(q) = sqrt(w*q/hbar);
waveF(q) = k*exp(-e(q)^2/2);
func(p,q) = waveF(q-x/2)*waveF(q+x/2)*exp(1i*p*x/(hbar));
res(p,q) = int(func(p,q),x,-Inf,Inf);
I wrapped the value of hbar in quotes to force the use of the supplied value and not the nearest rational representation that would've been coerced during computation.
Purely numeric version using anonymous functions and the numeric integral function:
w = 1;
hbar = 1.054571800E-34;
k = (w/(pi*hbar)).^(1/4);
e = #(q) sqrt(w*q/hbar);
waveF = #(q) k*exp(-e(q).^2/2);
func = #(p,q,x) waveF(q-x/2).*waveF(q+x/2).*exp(1i*p*x/hbar);
res = #(p,q) integral(#(x) func(p,q,x),-Inf,Inf);
Both of these version generate NaN when res is evaluated, but that's probably a shortcoming of the integrand. However, the functional forms and ideas behind the above scripts won't change with different integrands.

How to maintain the inassociativity in MATLAB code

I have a somewhat simple question but I couldn't reproduce the correct answer when transcription a Fortran-90 code to MATLAB.
The following MATLAB code is initialized using an integer i0 = 842739021913. This is a part of Fortran-90 code consist of a more general integer random number generator routine.
i0 = 842739021913 ;
function x_tdrand = tdrand
ia = int32(513) ; ib = int32(29741096258473) ; it = int32(140737488355328) ;
t = 1.40737488355328e14 ;
i0 = ia*i0+ib ;
i0 = i0-(i0/it)*it ;
x_tdrand = i0/t ;
end
The second calculation of i0 (i.e., i0=i0-(i0/it)*it) should give i0=39853749433858 in Fortran-90 (see below) but using MATLAB i obviously get zero.
Appreciate any of your advice of how to reproduce the Fortran code correctly.
SUBROUTINE TDRAND(X)
USE module_GENERAL, ONLY: I0
IMPLICIT NONE
INTEGER(8) :: IA, IB, IT
DOUBLE PRECISION :: X, T
DATA IA, IB, IT /513, 29741096258473, 140737488355328/
DATA T /1.40737488355328D14/
I0=IA*I0+IB
I0=I0-(I0/IT)*IT
X=DBLE(I0)/T
RETURN
END SUBROUTINE TDRAND

Undefined function 'F' for input arguments of type 'char'

I am trying to create a function F(t) that is equal to a convolution integral, and then compute theta_n(n+1) by taking the value F(tn). However, I'm getting the error "Undefined function 'F' for input arguments of type 'char'". What's the problem?
function [ theta ] = Untitled( theta_o,omega_o )
nt=5001; %since (50-0)/.01 = 5000
dt = .01; % =H
H=.01;
theta_n = ones(nt,1);
theta_n(1)=0; %theta_o
omega_n = ones(nt,1);
omega_n(1)=-0.4; %omega_o
epsilon=10^(-6);
eta = epsilon*10;
t_o=0;
for n=1:4999
tn=t_o+n*dt;
F := int((422.11/eta)*exp((5*(4*((eta*t-s-tn)^2)/eta^2)-1)^(-1))*omega, s,tn- (n/2),tn+(n/2))
theta_n(n+1) = theta_n(n) + h*F(tn);
end
end
What about F = #(tn) ...;?
Probably you mixed up some other things in this code as well, e.g. H vs. h and so on...

Error when Passing matrices from MATLAB to FORTRAN dll

I have a simple intel fortran dll compiled from below:
function add1(A,n)
!Expose function add1 to users of this DLL
!DEC$ ATTRIBUTES C,DLLEXPORT:: add1
implicit none
double precision A(n,n),add1(n,n)
integer n
call add2(A,n)
A=A+1.0
add1=A
end function add1
subroutine add2(a,n)
double precision a(n,n)
integer n
a=a+1
endsubroutine
I also have a header file for the dll:
double* add1(double*,int);
I use MATLAB to load the dll:
library='trydll.dll';
header='add1.h';
loadlibrary(library, header);
n=3;
haha=ones(n,n);
A=calllib('trydll','add1',haha,n)
unloadlibrary('trydll')
The sent matrix and the integer to the dll are severely wrong, and seem to be random numbers in the memory. Anyone has any idea where the mistake is?
Like Barron suggested, use a subroutine to make life easier. Let MATLAB allocate the memory.
Here's a full working example using Intel Fortran 12.1:
subroutine CopyArray(A, B, n)
!DEC$ ATTRIBUTES DLLEXPORT :: CopyArray
!DEC$ ATTRIBUTES ALIAS: 'CopyArray' :: CopyArray
!DEC$ ATTRIBUTES REFERENCE :: A, B
!DEC$ ATTRIBUTES VALUE :: n
real(8), intent(in), dimension(n,n) :: A(n,n)
real(8), intent(out), dimension(n,n) :: B(n,n)
integer, intent(in) :: n
B = A
end subroutine
Header file:
void CopyArray(double*, double*, int);
MATLAB script:
n = 3;
A = rand(n, n);
B = zeros(n, n);
[A2, B2] = calllib(libname, 'CopyArray', A, B, n);
Using the libpointer appears to be optional here. It appears that MATLAB automatically converts the array arguments to pointers. Also, note that the arguments that are passed by reference (A, B) are translated to function return values in MATLAB.
I'm not currently able to code up your example for thorough testing, but I can say from experience that I've never had much luck calling Fortran libraries from Matlab the way you've shown. Here's what I do:
Use subroutines instead of functions. So, convert add1 to be more like:
SUBROUTINE add1(n,Ain,Aout)
INTEGER, INTENT(in) :: n
REAL*8, INTENT(in) :: Ain(n,n)
REAL*8, INTENT(out) :: Aout(n,n)
Aout = Ain + 1d0
END SUBROUTINE
Then call from Matlab with something like:
n = 3;
Ain = ones(n,n);
Aout = libpointer('doublePtr',zeros(1,n));
calllib('trydll','add1',n,Ain,Aout);
Aout = Aout.value;
It's possible that it's only that last .value part that you really need, but I'm running off of memory here.
I guess that is a initialization problem. You can try the following script in MATLAB:
library='trydll.dll';
header='add1.h';
loadlibrary(library, header);
n=3;
arg_1 = libpointer('doublePtr',double(ones(1,n)))
arg_2 = libpointer('int32',n)
out_raw = libpointer('doublePtr')
[output, arg_1] = calllib('trydll','add1',arg_1, arg_2)
unloadlibrary('trydll')
To see the FORTRAN/DLL output:
out = get(out_raw,'Value')
for i=1:n
display(out[i]);
end