Today I'm trying to evaluate this differential equation for internal energy in a gas in Fortran 90:
du / dt = dT / dt = - λ / ρ
Where u is the internal energy and λ is the cooling function (and they are both functions of temperature T only). ρ is the mass density and we can assume it's constant.
I'm using a Runge-Kutta 2nd order method (heun), and I'm sure I wrote the actual solving algorithm correctly, but I'm pretty sure I'm messing up the implementation. I'm also not sure how to efficiently choose an arbitrary energy scale.
I'm implementing the Right Hand Side with this subroutine:
MODULE RHS
! right hand side
IMPLICIT NONE
CONTAINS
SUBROUTINE dydx(neq, y, f)
INTEGER, INTENT(IN) :: neq
REAL*8, DIMENSION(neq), INTENT(IN) :: y
REAL*8, DIMENSION(neq), INTENT(OUT) :: f
f(1) = -y(1)
END SUBROUTINE dydx
END MODULE RHS
And this is the Heun algorithm I'm using:
SUBROUTINE heun(neq, h, yold, ynew)
INTEGER, INTENT(IN) :: neq
REAL*8, INTENT(IN) :: h
REAL*8, DIMENSION(neq), INTENT(IN) ::yold
REAL*8, DIMENSION(neq), INTENT(OUT) :: ynew
REAL*8, DIMENSION(neq) :: f, ftilde
INTEGER :: i
CALL dydx(neq, yold, f)
DO i=1, neq
ynew(i) = yold(i) + h*f(i)
END DO
CALL dydx(neq, ynew, ftilde)
DO i=1, neq
ynew(i) = yold(i) + 0.5d0*h*(f(i) + ftilde(i))
END DO
END SUBROUTINE heun
Considering both lambda and rho are n-dimensional arrays, i'm saving the results in an array called u_tilde, selecting a starting condition at T = 1,000,000 K
h = 1.d0/n
u_tilde(1) = lambda(n)/density(n) ! lambda(3) is at about T=one million
DO i = 2, n
CALL heun(1, h*i, u_tilde(i-1), u_tilde(i))
ENDDO
This gives me this weird plot for temperature over time.
I would like to have a starting temperature of one million kelvin, and then have it cool down to 10.000 K and see how long it takes. How do I implement these boundary conditions?
What am I doing wrong in RHS and in setting up the calculation loop in the program?
Your implementation of dydx only assigns the first element.
Also, there is no need to define loops for each step, as Fortran90 can do vector operations.
For a modular design, I suggest implementing a custom type that holds your model data, like the mass density and the cooling coefficient.
Here is an example simple implementation, that only holds one scalar value, such that y' = -c y
module mod_diffeq
use, intrinsic :: iso_fortran_env, wp => real64
implicit none
type :: model
real(wp) :: coefficient
end type
contains
pure function dxdy(arg, x, y) result(yp)
type(model), intent(in) :: arg
real(wp), intent(in) :: x, y(:)
real(wp) :: yp(size(y))
yp = -arg%coefficient*y
end function
pure function heun(arg, x0, y0, h) result(y)
type(model), intent(in) :: arg
real(wp), intent(in) :: x0, y0(:), h
real(wp) :: y(size(y0)), k0(size(y0)), k1(size(y0))
k0 = dxdy(arg, x0, y0)
k1 = dxdy(arg, x0+h, y0 + h*k0)
y = y0 + h*(k0+k1)/2
end function
end module
and the above module is used for some cooling simulations with
program FortranCoolingConsole1
use mod_diffeq
implicit none
integer, parameter :: neq = 100
integer, parameter :: nsteps = 256
! Variables
type(model):: gas
real(wp) :: x, y(neq), x_end, h
integer :: i
! Body of Console1
gas%coefficient = 1.0_wp
x = 0.0_wp
x_end = 10.0_wp
do i=1, neq
if(i==1) then
y(i) = 1000.0_wp
else
y(i) = 0.0_wp
end if
end do
print '(1x," ",a22," ",a22)', 'x', 'y(1)'
print '(1x," ",g22.15," ",g22.15)', x, y(1)
! Initial Conditions
h = (x_end - x)/nsteps
! Simulation
do while(x<x_end)
x = x + h
y = heun(gas, x, y, h)
print '(1x," ",g22.15," ",g22.15)', x, y(1)
end do
end program
Note that I am only tracking the 1st element of neq components of y.
The sample output shows exponential decay starting from 1000
x y(1)
0.00000000000000 1000.00000000000
0.390625000000000E-01 961.700439453125
0.781250000000000E-01 924.867735244334
0.117187500000000 889.445707420492
0.156250000000000 855.380327695983
0.195312500000000 822.619637044785
0.234375000000000 791.113666448740
0.273437500000000 760.814360681126
0.312500000000000 731.675505009287
0.351562500000000 703.652654704519
0.390625000000000 676.703067251694
0.429687500000000 650.785637155231
0.468750000000000 625.860833241968
0.507812500000000 601.890638365300
0.546875000000000 578.838491418631
0.585937500000000 556.669231569681
...
Also, if you wanted the above to implement runge-kutta 4th order you can include the following in the mod_diffeq module
pure function rk4(arg, x0, y0, h) result(y)
type(model), intent(in) :: arg
real(wp), intent(in) :: x0, y0(:), h
real(wp) :: y(size(y0)), k0(size(y0)), k1(size(y0)), k2(size(y0)), k3(size(y0))
k0 = dxdy(arg, x0, y0)
k1 = dxdy(arg, x0+h/2, y0 + (h/2)*k0)
k2 = dxdy(arg, x0+h/2, y0 + (h/2)*k1)
k3 = dxdy(arg, x0+h, y0 + h*k2)
y = y0 + (h/6)*(k0+2*k1+2*k2+k3)
end function
Related
A Fortran code has two definitions of a subroutine within an if defined block, as shown below. If I manually remove of the definitions, the code can be compiled, but that's not what the author intended. Compiling with gfortran -c -cpp does not work. What is the right way to compile it?
#:if defined('SLICOT')
subroutine dlyap(TT, RQR, P0, ns, info)
! Computes the solution to the discrete Lyapunov equation,
! P0 = TT*P0*TT' + RQR
! where (inputs) TT, RQR and (output) P0 are ns x ns (real) matrices.
!--------------------------------------------------------------------------------
integer, intent(in) :: ns
real(wp), intent(in) :: TT(ns,ns), RQR(ns,ns)
integer, intent(out) :: info
real(wp), intent(out) :: P0(ns,ns)
! for slicot
real(wp) :: scale, U(ns,ns), UH(ns, ns), rcond, ferr, wr(ns), wi(ns), dwork(14*ns*ns*ns), sepd
integer :: iwork(ns*ns), ldwork
integer :: t
UH = TT
P0 = -1.0_wp*RQR
!call sb03md('D','X', 'N', 'T', ns, UH, ns, U, ns, P0, ns, &
! scale, sepd, ferr, wr, wi, iwork, dwork, 14*ns*ns*ns, info)
!if (ferr > 0.000001_wp) call dlyap_symm(TT, RQR, P0, ns, info)
if (info .ne. 0) then
print*,'SB03MD failed. (info = ', info, ')'
P0 = 0.0_wp
info = 1
do t = 1,ns
P0(t,t)=1.0_wp
end do
return
else
! P0 = 0.5_wp*P0 + 0.5_wp*transpose(P0)
info = 0
end if
end subroutine dlyap
#:else
! from elmar
SUBROUTINE DLYAP(A, QQ, Sigma, nx, status)
! doubling, calling DSYMM and DGEMM
! Sigma = A * Sigma * A' + B * B'
! output Sigma is symmetric
IMPLICIT NONE
integer, intent(in) :: nx
integer, intent(out) :: status
real(wp), intent(in) :: QQ(nx,nx), A(nx,nx)
real(wp), intent(out) :: Sigma(nx,nx)
INTEGER, PARAMETER :: maxiter = 100
DOUBLE PRECISION, PARAMETER :: tol = 1.0d-8
INTEGER :: iter, i
LOGICAL :: converged
DOUBLE PRECISION, DIMENSION(Nx,Nx) :: AA, AAA, AASigma, Sigma0
Sigma0 = QQ
! Sigma0 = B B'
! Sigma0 = 0.0d0
! call DSYRK('U','N',Nx,Nw,1.0d0,B,Nx,0.0d0,Sigma0,Nx)
! ! fill up lower triangular -- necessary for DGEMM below
! FORALL (i=2:Nx) Sigma0(i,1:i-1) = Sigma0(1:i-1,i)
converged = .false.
iter = 0
AA = A
DO
iter = iter + 1
! call sandwichplus(Sigma, AA, Nx, Sigma0, Nx)
! MANUAL SANDWICHPLUS: Sigma = AA * Sigma0 * AA' + Sigma
call DSYMM('R','U',Nx,Nx,1.0d0,Sigma0,Nx,AA,Nx,0.0d0,AASigma,Nx)
Sigma = Sigma0 ! this line requires Sigma0 to
call DGEMM('N','T',Nx,Nx,Nx,1.0d0,AASigma,Nx,AA,Nx,1.0d0,Sigma,Nx)
! balance for symmetry
Sigma = 0.5d0 * (Sigma + transpose(Sigma))
IF (abs(maxval(Sigma - Sigma0)) < tol) converged = .true.
! print *, iter, abs(maxval(Sigma - Sigma0)), tol
! Sigma = (Sigma + transpose(Sigma)) / dble(2)
IF (converged .OR. (iter > maxiter)) EXIT
! AAA = AA * AA
call DGEMM('N','N',Nx,Nx,Nx,1.0d0,AA,Nx,AA,Nx,0.0d0,AAA,Nx)
AA = AAA
Sigma0 = Sigma
END DO
IF (converged) THEN
status = 0
ELSE
status = -1
END IF
END SUBROUTINE DLYAP
#:endif
Thank you guys, all your advices are relevant, but I gave up of Fortran and translated my code to Python. There, with just 1 or 2 little bugs my code worked perfect
I wrote a program to solve a linear system using the Gauss method. I wrote all the algorithms, the forward elimination and the back substitution and I made a lot of others subroutines and I don't know anymore what's wrong, I don't if is something wrong with my code or if some problem programming in Fortran because I'm new in this language. I'll put my code below and the linear system that I should find a solution
PROGRAM metodo_Gauss
IMPLICIT NONE
REAL :: det_a_piv
INTEGER :: n, i, j
REAL, DIMENSION(:,:), ALLOCATABLE :: a, a_piv
INTEGER, DIMENSION(:), ALLOCATABLE :: p
REAL, DIMENSION(:), ALLOCATABLE :: b, x
PRINT*, "Entre com a dimensão n do sistema a ser resolvido"
READ*, n
! allocate memory
ALLOCATE(a(n, n))
ALLOCATE(a_piv(n, n))
ALLOCATE(p(n))
ALLOCATE(b(n))
ALLOCATE(x(n))
CALL matriz_a(n, a)
CALL vetor_b(n, b)
a_piv(1:n, 1:n) = a(1:n, 1:n)
DO i = 1, n
x(i) = 0
END DO
CALL eliminacao(n, a, a_piv, p)
det_a_piv = (-1) ** n
DO j = 1, n
det_a_piv = det_a_piv * a_piv(j, j)
END DO
IF (det_a_piv == 0) THEN
PRINT*, "O sistema linear é indeterminado"
ELSE IF (abs(det_a_piv) <= 1) THEN
PRINT*, "O sistema linear é mal-condicionado"
ELSE
CALL substituicao(n, a_piv, p, b, x)
PRINT*, "A solução do sistema é:"
PRINT*, x
END IF
END PROGRAM metodo_Gauss
SUBROUTINE matriz_a(n, a)
IMPLICIT NONE
INTEGER, INTENT(in) :: n
REAL, DIMENSION(n,n), INTENT(inout) :: a
INTEGER :: i, j !Indícios usados em loops para percorrer os arrays
PRINT*, "Por favor digite os valores do elementos da matriz sistema linear seguindo pela ordem das linhas até o final:"
DO i = 1, n
DO j = 1, n
READ*, a(i,j)
END DO
END DO
END SUBROUTINE matriz_a
SUBROUTINE vetor_b(n, b)
IMPLICIT NONE
INTEGER, INTENT(in) :: n
REAL, DIMENSION(n), INTENT(inout) :: b
INTEGER :: i
PRINT*, "Por favor entre com os elementos do vetor b:"
DO i = 1, n
READ*, b(i)
END DO
END SUBROUTINE vetor_b
SUBROUTINE eliminacao(n, a, a_piv, p)
IMPLICIT NONE
INTEGER, INTENT(in) :: n
REAL, DIMENSION(n, n), INTENT(in) :: a
REAL, DIMENSION(n, n), INTENT(out) :: a_piv
INTEGER, DIMENSION(n), INTENT(out) :: p
INTEGER :: i, j, local, dim
REAL :: mult
DO i = 1, (n - 1)
dim = n - 1
CALL local_pivo(dim, a(i:n, i), local)
a_piv(i, i:n) = a(local, i:n)
a_piv(local, i:n) = a(i, i:n)
p(i) = local
DO j = (i + 1), n
mult = (-1) * (a_piv(j,i) / a_piv(local,i))
a_piv(j,i) = mult
a_piv(j, j:n) = a_piv(j, j:n) + mult * a_piv(i, j:n)
END DO
END DO
END SUBROUTINE eliminacao
SUBROUTINE local_pivo(n, a, local)
IMPLICIT NONE
INTEGER, INTENT(in) :: n
REAL, DIMENSION(n), INTENT(in) :: a
INTEGER, INTENT(inout) :: local
INTEGER :: i
local = 1
DO i = 2, n
IF ((ABS(a(i))) > ABS(a(local))) THEN
local = i
END IF
END DO
END SUBROUTINE local_pivo
SUBROUTINE substituicao(n, a_piv, p, b, x)
IMPLICIT NONE
INTEGER, INTENT(in) :: n
REAL, DIMENSION(n, n), INTENT(in) :: a_piv
REAL, DIMENSION(n), INTENT(out) :: b, x
INTEGER, DIMENSION(n), INTENT(in) :: p
INTEGER :: i, j, k, l, pivo
REAL :: aux
DO i = 1, (n - 1)
pivo = p(i)
IF (pivo /= i) THEN
aux = b(i)
b(i) = b(pivo)
b(pivo) = aux
END IF
DO j = (i + 1), n
b(j) = a_piv(j, i) * b(j) + b(i)
END DO
END DO
DO k = n, 1, -1
IF (k == n) THEN
x(n) = b(n) / a_piv(n, n)
ELSE
x(k) = (b(k) + a_piv(k, n) * x(n)) / a_piv(k, k)
DO l = n, k, -1
x(l) = x(l) + (a_piv(k, l) * x(l)) / a_piv(k, k)
END DO
END IF
END DO
END SUBROUTINE substituicao
Here it is the system that I'm trying to solve
My input is:
4
4
3
2
2
2
1
1
2
2
2
2
4
6
1
1
2
5
8
3
1
My output is:
-40.5000000 -40.2500000 -3.75000000 -37.5000000
But the output should be:
6.500000
-44.000000
72.000000
-16.500000
The solution for this double integration is -0.083 but in the final compliation it appears -Infinity. It seems that the error is very simple, but I really can't find it.
I have been searching specially in the module section but I don't see why it appears like -Infinity. For example, if you change the two functions between them (x in f2 and x^2 in f1) the solution for the integration is 0.083 and the code gives it correct. Can annyone find the error? Thanks a lot.
module funciones
contains
function f(x,y)
implicit none
real*8:: x,y,f
f=2d0*x*y
end function
function f1(x)
real*8::x,f1
f1=x
end function
function f2(x)
real*8::x,f2
f2=x**2d0
end function
function g(x,c,d,h)
implicit none
integer::m,j
real*8::x,y,c,d,k,s,h,g
m=nint(((d-c)/h)+1d0)
k=(d-c)/dble(m)
s=0.
do j=1d0,m-1d0
y=c+dble(j)*k
s=s+f(x,y)
end do
g=k*(0.5d0*(f(x,c)+f(x,d))+s)
return
end function
subroutine trapecio(a,b,n,integral)
implicit none
integer::n,i
real*8::a,b,c,d,x,h,s,a1,a2,b1,b2,integral
h=(b-a)/dble(n)
s=0d0
do i=1d0,n-1d0
x=a+dble(i)*h
c=f1(x)
d=f2(x)
s=s+g(x,c,d,h)
end do
a1=f1(a)
a2=f2(a)
b1=f1(b)
b2=f2(b)
integral=h*(0.5d0*g(a,a1,a2,h)+0.5d0*g(b,b1,b2,h)+s)
end subroutine
end module
program main
use funciones
implicit none
integer::n,i
real*8::a,b,c,d,x,s,h,integral
print*, "introduzca los valores de a, b y n"
read(*,*) a, b, n
call trapecio (a,b,n,integral)
print*,integral
end program
The main program is simple, just calling the subroutine and using the module. It also prints the final result.
First of all, like mentioned in the comments: your problem is not clear. Which input parameters a, b and n do you use and which result do you expect?
Other than that: the code you posted used deprecated features and non-standard types and bad code style.
Some general hints:
real*8 is non-standard Fortran. Use real(real64) instead. real64 has to be imported by use :: iso_fotran_env, only: real64.
non-integer expressions (do i=1d0,n-1d0) in do-loops are a deleted feature in modern Fortran. Use integers instead.
code should be formatted with white spaces and indentations
print*, should be replaced with write(*,*)
code should always use English names
write implicit none in the beginning of the module, not for every function.
make the module/program interface clear by using the statements private, public, and only
if You want to convert to type real, use the function REAL instead of DBLE
I prefer the cleaner function definition using result
use intent keywords: intent(in) passes the variable as a const reference.
the variables c,d,x,s,h in the main program are unused. Compile with warnings to detect unused variables.
This is the code changed with the suggestions I made:
module funciones
use :: iso_fortran_env, only: real64
implicit none
private
public :: trapecio, r8
integer, parameter :: r8 = real64
contains
function f(x,y) result(value)
real(r8), intent(in) :: x,y
real(r8) :: value
value = 2._r8*x*y
end function
function f1(x) result(value)
real(r8), intent(in) :: x
real(r8) :: value
value = x
end function
function f2(x) result(value)
real(r8), intent(in) :: x
real(r8) :: value
value = x**2._r8
end function
function g(x,c,d,h) result(value)
real(r8), intent(in) :: x, c, d, h
real(r8) :: value
real(r8) :: y, k, s
integer :: m, j
m = NINT(((d-c)/h)+1._r8)
k = (d-c)/REAL(m, r8)
s = 0._r8
do j = 1, m-1
y = c + REAL(j,r8)*k
s = s + f(x,y)
end do
value = k*(0.5_r8*(f(x,c)+f(x,d))+s)
end function
subroutine trapecio(a, b, n, integral)
real(r8), intent(in) :: a, b
integer, intent(in) :: n
real(r8), intent(out) :: integral
integer :: i
real(r8) :: c, d, x, h, s, a1, a2, b1, b2
h = (b-a)/REAL(n,r8)
s = 0._r8
do i = 1, n-1
x = a + REAL(i,r8)*h
c = f1(x)
d = f2(x)
s = s + g(x,c,d,h)
end do
a1 = f1(a)
a2 = f2(a)
b1 = f1(b)
b2 = f2(b)
integral = h*(0.5_r8*g(a,a1,a2,h) + 0.5_r8*g(b,b1,b2,h) + s)
end subroutine
end module
program main
use funciones, only: trapecio, r8
implicit none
integer :: n,i
real(r8) :: a,b,integral
write(*,*) "introduzca los valores de a, b y n"
read(*,*) a, b, n
call trapecio (a,b,n,integral)
write(*,*) integral
end program
My problem is to pass the names of a series of functions contained in a module to a subroutine in a do loop.
I post part of my code. The modules are in two separate files compared to the main.
%%% FILE testKer_mod.f90
module kernel
implicit none
contains
! POLYNOMIAL
function poly(x, ts, ndim, a, param1, param2)
integer, intent (in) :: ndim
real*8, dimension(ndim), intent(in) :: x
real*8, dimension(ndim), intent(in) :: ts
real*8, intent(in) :: a, param1, param2
real*8 :: r
real*8 :: poly
r = (x(1:ndim) - ts(1:ndim))
poly = r**(.5*a)
end function poly
! GAUSSIAN
function gauss(x, ts, ndim, a, gamma, param2)
integer, intent (in) :: ndim
real*8, dimension(ndim), intent(in) :: x
real*8, dimension(ndim), intent(in) :: ts
real*8, intent(in) :: a, param2, gamma
real*8 :: r
real*8 :: gauss
r = (x(1:ndim) - ts(1:ndim))
gauss = exp(-(gamma*r)**a)
end function gauss
end module kernel
%%%
%%% FILE testSRBF_mod.f90
module srbf
implicit none
contains
subroutine weigth(nx, x, nts, ts, ndim, s, kernel, StocPar, param, coe, mat)
integer :: i,j,k,l,m,n
integer :: info
integer :: nx, nts, ndim
integer, dimension(nts) :: ipiv
real*8, dimension(nts) :: w
real*8, dimension(nts) :: s
real*8, dimension(2) :: param
real*8, dimension(nx,ndim) :: x
real*8, dimension(nts,ndim) :: ts
real*8, dimension(nx,nts) :: phi, mat
real*8, dimension(nts) :: coe
real*8 :: stocPar
interface
real*8 function kernel(x1, x2, n3, stov, p1, p2)
integer, intent (in) :: n3
real*8, dimension(n3), intent(in) :: x1
real*8, dimension(n3), intent(in) :: x2
real*8, intent(in) :: stov, p1, p2
end function kernel
end interface
do i = 1, nx
do j = 1, nts
phi(i,j) = kernel(x(i,1:ndim), ts(j,1:ndim), ndim, stocPar, param(1), param(2))
end do
end do
w = s
mat = phi
call DGESV(nts,1,mat,nts,ipiv,w,nts,info)
coe = w
end subroutine weigth
end module srbf
%%%
%%% MAIN PROGRAM test.f90
program MKRBF
use kernel
use srbf
implicit none
!real*8 :: SelKer
integer :: i,j,k
integer, parameter :: n = 3
integer, parameter :: nKer = 2
real*8, dimension(2,2) :: ParBound, auxpar
real*8, dimension(2) :: Bound
real*8, dimension(n) :: Var, func
real*8, dimension(n,nKer) :: coe
real*8, dimension(n,n) :: mat
!external SelKer
interface
real*8 function SelKer(ind)
integer, intent (in) :: ind
end function SelKer
end interface
Bound(1) = 0
Bound(2) = 5
ParBound(1,1) = 1
ParBound(1,2) = 5
ParBound(2,1) = 1
ParBound(2,2) = 5
auxpar(1,1) = 0
auxpar(1,2) = 0
auxpar(2,1) = 1
auxpar(2,2) = 1
var(:) = (/ 0., 2.5, 5. /)
do i = 1, n
func(i) = cos(3*Var(i)) * exp(-.25*Var(i));
end do
do i = 1, nKer
call weigth(n,Var,n,Var,1,func,SelKer(i),2.0D0,auxpar,coe,mat)
end do
end program MKRBF
function SelKer(indx)
integer, intent(in) :: indx
real*8 :: SelKer
select case (indx)
case (1)
SelKer = poly
case (2)
SelKer = gauss
end select
return
end function SelKer
%%%
I tried both with interface and with external but the program gives me the same error:
gfortran testKer_mod.f90 testSRBF_mod.f90 test.f90 -llapack -o test
test.f90:46:38:
call weigth(n,Var,n,Var,1,func,SelKer(i),2.0D0,auxpar,coe,mat)
1
Error: Expected a procedure for argument 'kernel' at (1)
How can I fix it?
Looking at the interface block in the main program
interface
real*8 function SelKer(ind)
integer, intent (in) :: ind
end function SelKer
end interface
SelKer is a function with real*8 result.1 SelKer(i) is such a function result. Crucially, SelKer(i) isn't a function with real*8 result, but such a real*8 value. weigth is expecting the argument for kernel to be a function (which is a procedure). This is the error message.
Coming to how the external function SelKer is implemented: we see such things as
SelKer = poly
In the function poly isn't the function poly in the module kernel but a local (default) real scalar variable (with undefined value). Note the lack of implicit none in the function.
Instead, you want to be looking to be using procedure pointers. This is a broad topic, so I'll just give an indication of the approach.
Move SelKer to be a procedure in the module kernel (removing the corresponding interface block from the main program).
Declare the function result SelKer to have type procedure(poly).
Use pointer assignment for the result, like SelKer => gauss.
There are other, perhaps better ways, to structure such a program. In particular, many would advise against using procedure pointer function results.
1 real*8 isn't standard Fortran.
when executing this function:
FUNCTION gaussian_elimination(A, C) result(X)
implicit none
real, intent(inout) :: C(:), A(size(C), size(C))
real :: X(size(C))
real :: D(size(C))
integer :: i, j, neq
neq = size(C)
! Forward reduction, only two loops since reduction is now row by row
do i = 1, neq
D = A(:,i)/A(i,i)
do j = i+1, neq
A(j,:) = A(j,:) - D(j)*A(i,:)
C(j) = C(j) - D(j)*C(i)
enddo
enddo
! Back substitution, only one loop
do i = neq, 1, -1
x(i) = (C(i) - sum(A(i, i+1:) * x(i+1:))) / A(i,i)
enddo
end FUNCTION gaussian_elimination
With the following:
real , DIMENSION(6,6) :: K
real , DIMENSION(6,1) :: R
real , DIMENSION(6,1) :: n
n = gaussian_elimination(K,R)
Result:
n = gaussian_elimination(K,R)
1
Error: Incompatible ranks 2 and 1 in assignment at (1)
You need to specify a second dimension to X if n should be of DIMENSION(6,1):
real :: X(size(C,1),size(C,2))
Note, that you additionally have the dummy arguments specified wrong... It should probably read:
FUNCTION gaussian_elimination(A, C) result(X)
implicit none
real, intent(inout) :: C(:,:), A(size(C,1), size(C,1))
real :: X(size(C,1),size(C,2))
...
Alternatively, you could define R and n as
real , DIMENSION(6) :: R
real , DIMENSION(6) :: n
and leave your code unchanged.
Option three: You work with array slices:
n(:,1) = gaussian_elimination(K,R(:,1))
No changes in the code...