Matrix multiplication program: Error: Unclassifiable statement at (1) - fortran

I am a very new user to Fortran 90. I am learning how to program. Currently, I am trying to create a program to do matrix multiplication. But, I am getting an error.
Program Matrix_Multiplication
Implicit None
Real, Dimension(2:2) :: A, B, C
Integer :: i, j, k
A = 0.0
B = 0.0
C = 0.0
do i = 1, 2
do j = 1, 2
Read (80, *) A
Read (90, *) B
Write (100, *) A, B
end do
end do
Call subC(A, B, C)
Write (110, *) C
End Program Matrix_Multiplication
Subroutine subC(A, B, C)
Implicit None
Real, Intent(IN) :: A, B
Integer :: i, j, k
Real, Intent(OUT) :: C
do i = 1, 2
do j = 1, 2
C = C(i, j) + (A(i, j)*B(j, i))
end do
end do
return
End Subroutine
On compiling:
C(i, j) = (A(i, k)*B(k, j)) 1 Error: Unclassifiable statement at (1)

As francescalus stated in his comment, A, B, and C are declared as scalars inside the subroutine. Therefore, you cannot index them as arrays.
In this particular case I would rather use the intrinsic function matmul instead of writing your own matrix-matrix multiplication:
Program Matrix_Multiplication
Implicit None
Real, Dimension (2,2) :: A,B,C
A=0.0
B=0.0
C=0.0
do i=1,2
do j=1,2
Read (80,*) A(j,i)
Read (90,*) B(j,i)
Write (100,*) A,B
end do
end do
C = matmul(A,B)
Write (110,*) C
End Program Matrix_Multiplication
For larger matrices there are highly optimized math-libraries out there. Using BLAS/LAPACK is highly recommended then. The correct subroutine for your example would be SGEMM.

More of a formatted comment than an answer but the declaration
Real, Dimension (2:2) :: A,B,C
declares A,B and C to be rank-1 arrays of 0 elements. You probably ought to rewrite the statement as
Real, Dimension (2,2) :: A,B,C
which declares the arrays to be rank-2 and 2x2.

Related

How do I define integer array for given variable nBoxes [duplicate]

I'm writing a code for LU decomposition and I don't know how to fix the "unexpected data declaration statement" pointed at line 8 (where I'm declaring an array. See the code fragment). Why is it unexpected?
!Decomposição LU
!-----------------------------------------------------------
PROGRAM LUdecomp
IMPLICIT INTEGER (I-K,N), REAL (A-H, L-M,O-Z)
INTEGER, PARAMETER :: N=3
REAL, DIMENSION (N,N) :: A,L,U
A = reshape((/3.,1.,4.,4.,2.,0.,3.,2.,3./),(/3,3/)) !exemplo do Bortoli*******
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
OPEN(1,file = 'LUFACTOR.out')
!
! FORALL (I = 1:N, J = 1:N) A(I,J) = 1.0/REAL(I+J-1)
!-------Fazendo a fatoração A = LU-----------------------------
CALL LU(N, A, L, U)
DO I=1,N
WRITE(*,10)(L(I,J), J=1,N), (U(I,J), J=1,N)
END DO
10 FORMAT(3(F8.4), 7x, 3(F8.4))
!
This statement
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
is in the wrong place. In a Fortran program-unit (program, subroutine, function) -- certainly one without the new ASSOCIATE and BLOCK constructs -- all declarations have to precede all executable statements.
Move the misplaced statement ahead of the first executable statement.

Fortran Error: Rank mismatch in array reference (2/1) [duplicate]

I kindly request your help on this code where I kept on getting
an error: Rank mismatch in array reference at (1) (2/1). My objective is to go through each point in a cube(p = i+(j-1)*N + (k-1)NN) and calculate the gradient of the potential along each axis (gradphi_x, gradphi_y, gradphi_z).
PROGRAM sub_rho_phi
integer, parameter:: N=3
real, dimension(N):: gradphi_x, gradphi_y, gradphi_z
call output(gradphi_x, gradphi_y, gradphi_z)
open(unit=1,file="grad_phi.dat")
l = 0
do
l=l+1
write(1,*) gradphi_x(l),gradphi_y(l),gradphi_z(l)
if ( l == N**3) then
exit
end if
end do
END
SUBROUTINE output( gradphi_x, gradphi_y, gradphi_z )
real, parameter:: h=0.7,G=6.67,M=1.98892*(10**3)!!in(10**15) kg
integer, parameter:: N=3
real, dimension(N):: r, gradphi_x,gradphi_y,gradphi_z
integer, dimension(N**3):: x,y,z
integer:: p
real:: a
a=500/h !in kpc
do i=0, N
do j=0, N
do k=0, N
p = i+(j-1)*N + (k-1)*N*N
x(p,1)=i
y(p,2)=j
z(p,3)=k
r(p)=sqrt(x(p,1)*x(p,1)+y(p,2)*y(p,2)+z(p,3)*z(p,3))
gradphi_x(p)=(G*M)*x(p,1)/r(p)*(r(p)+a)**2
gradphi_y(p)=(G*M)*y(p,2)/r(p)*(r(p)+a)**2
gradphi_z(p)=(G*M)*z(p,3)/r(p)*(r(p)+a)**2
enddo
enddo
enddo
return
END
You have declared x, y and z as one dimensional arrays, but are using two dimensional indexing all the way through output.

Using Minpack to solve S-curve

I'd like to use Minpack (fortran) to estimate the D parameter in the following generalized form of the S-curve: y = (A - D) / (1 + (x**B/C)) + D
The idea is that in this application, the user provides A [which is always 0 to force passage through (0,0)], B, and C, and from there Minpack will find a value for D that forces passage through (1,y), where y is also supplied by the user but must be <= 1. I was able to accomplish this task with the code below, however, minpack is claiming it hasn't converged when in fact it appears that it has. For example, when running this code and entering the values 1 (at the first prompt) and 0 4 0.1 (at the second prompting), minpack returns info = 2, which according to the comments in lmdif means:
relative error between two consecutive iterates is at most xtol.
I'm tempted to comment out line 63, but am worried that's playing with fire...are there any seasoned minpack users out there who could comment on this? Line 63 is the one that reads:
if (info /= 1) stop "failed to converge"
Am I mis-using Minpack even though it appears to converge (based on my verifying the value in pars)?
module types
implicit none
private
public dp
integer, parameter :: dp=kind(0d0)
end module
module f_vals
DOUBLE PRECISION, SAVE, DIMENSION(:), POINTER:: fixed_vals
end module
module find_fit_module
! This module contains a general function find_fit() for a nonlinear least
! squares fitting. The function can fit any nonlinear expression to any data.
use minpack, only: lmdif1
use types, only: dp
implicit none
private
public find_fit
contains
subroutine find_fit(data_x, data_y, expr, pars)
! Fits the (data_x, data_y) arrays with the function expr(x, pars).
! The user can provide any nonlinear function 'expr' depending on any number of
! parameters 'pars' and it must return the evaluated expression on the
! array 'x'. The arrays 'data_x' and 'data_y' must have the same
! length.
real(dp), intent(in) :: data_x(:), data_y(:)
interface
function expr(x, pars) result(y)
use types, only: dp
implicit none
real(dp), intent(in) :: x(:), pars(:)
real(dp) :: y(size(x))
end function
end interface
real(dp), intent(inout) :: pars(:)
real(dp) :: tol, fvec(size(data_x))
integer :: iwa(size(pars)), info, m, n
real(dp), allocatable :: wa(:)
tol = sqrt(epsilon(1._dp))
!tol = 0.001
m = size(fvec)
n = size(pars)
allocate(wa(m*n + 5*n + m))
call lmdif1(fcn, m, n, pars, fvec, tol, info, iwa, wa, size(wa))
open(222, FILE='D_Value.txt')
write(222,4) pars(1)
4 format(E20.12)
close(222)
if (info /= 1) stop "failed to converge"
contains
subroutine fcn(m, n, x, fvec, iflag)
integer, intent(in) :: m, n, iflag
real(dp), intent(in) :: x(n)
real(dp), intent(out) :: fvec(m)
! Suppress compiler warning:
fvec(1) = iflag
fvec = data_y - expr(data_x, x)
end subroutine
end subroutine
end module
program snwdeplcrv
! Find a nonlinear fit of the form y = (A - D) / (1 + (x**B/C)) + D.
use find_fit_module, only: find_fit
use types, only: dp
use f_vals
implicit none
real(dp) :: pars(1), y_int_at_1
real(dp) :: y(1) = 1.0 ! Initialization of value to be reset by user (y: value of S-curve # x=1)
real(dp) :: A, B, C
integer :: i
allocate(fixed_vals(3)) ! A, B, C parameters
pars = [1._dp] ! D parameter in S-curve function
! Read PEST-specified parameters
write(*,*) ' Enter value that S-curve should equal when SWE=1 (must be <= 1)'
read(*,*) y_int_at_1
if(y_int_at_1 > 1.0) y_int_at_1 = 1
y = y_int_at_1
! Read PEST-specified parameters
write(*,*) ' Enter S-curve parameters: A, B, & C. D parameter to be estimated '
read(*,*) A, B, C
fixed_vals(1) = A
fixed_vals(2) = B
fixed_vals(3) = C
call find_fit([(real(i, dp), i=1,size(y))], y, expression, pars)
print *, pars
contains
function expression(x, pars) result(y)
use f_vals
real(dp), intent(in) :: x(:), pars(:)
real(dp) :: y(size(x))
real(dp) :: A, B, C, D
A = fixed_vals(1)
B = fixed_vals(2)
C = fixed_vals(3)
D = pars(1)
y = (A - D) / (1 + (x**B / C)) + D
end function
end program

How to generate Fortran subroutine with SymPy codegen

I want to generate a Fortran subroutine with SymPy codegen utility. I can generate a Fortran function without problem with codegen(("f", x*y*z), "f95", "filename"). But I want to generate a Fortran subroutine so I can modify input arrays. How can I do this? The documentation is very poor.
The codegen utility creates a function if there is a single scalar return value, and a subroutine otherwise. There is some support for arrays, but the array functionality won't be triggered unless you feed codegen an array like expression. The documentation is scattered, so I'll give you some pointers:
Take a look at the matrix-vector example in the autowrap documentation: http://docs.sympy.org/latest/modules/utilities/autowrap.html. Autowrap uses codegen behind the scenes.
In the current developer version there is also functionality for generating code that correspond to matrices with symbolic elements. See the examples for fcode() at http://docs.sympy.org/dev/modules/printing.html#fortran-printing.
Here is sample code that should output a Fortran 95 subroutine for a matrix-vector product:
from sympy import *
from sympy.utilities.codegen import codegen
A, B, C = symbols('A B C', cls=IndexedBase)
m, n = symbols('m n', integer=True)
i = Idx('i', m)
j = Idx('j', n)
expr = Eq(C[i], A[i, j]*B[j])
result = codegen(('my_function', expr), 'f95', 'my_project')
print result[0][1]
By saving these lines to my_file.py and running python my_file.py, I get the following output:
!******************************************************************************
!* Code generated with sympy 0.7.5-git *
!* *
!* See http://www.sympy.org/ for more information. *
!* *
!* This file is part of 'project' *
!******************************************************************************
subroutine my_function(A, B, m, n, C)
implicit none
INTEGER*4, intent(in) :: m
INTEGER*4, intent(in) :: n
REAL*8, intent(in), dimension(1:m, 1:n) :: A
REAL*8, intent(in), dimension(1:n) :: B
REAL*8, intent(out), dimension(1:m) :: C
INTEGER*4 :: i
INTEGER*4 :: j
do i = 1, m
C(i) = 0
end do
do i = 1, m
do j = 1, n
C(i) = B(j)*A(i, j) + C(i)
end do
end do
end subroutine

Unexpected data declaration statement

I'm writing a code for LU decomposition and I don't know how to fix the "unexpected data declaration statement" pointed at line 8 (where I'm declaring an array. See the code fragment). Why is it unexpected?
!Decomposição LU
!-----------------------------------------------------------
PROGRAM LUdecomp
IMPLICIT INTEGER (I-K,N), REAL (A-H, L-M,O-Z)
INTEGER, PARAMETER :: N=3
REAL, DIMENSION (N,N) :: A,L,U
A = reshape((/3.,1.,4.,4.,2.,0.,3.,2.,3./),(/3,3/)) !exemplo do Bortoli*******
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
OPEN(1,file = 'LUFACTOR.out')
!
! FORALL (I = 1:N, J = 1:N) A(I,J) = 1.0/REAL(I+J-1)
!-------Fazendo a fatoração A = LU-----------------------------
CALL LU(N, A, L, U)
DO I=1,N
WRITE(*,10)(L(I,J), J=1,N), (U(I,J), J=1,N)
END DO
10 FORMAT(3(F8.4), 7x, 3(F8.4))
!
This statement
REAL, DIMENSION(3) :: B=(/9.,3.,-2./),Z,X
is in the wrong place. In a Fortran program-unit (program, subroutine, function) -- certainly one without the new ASSOCIATE and BLOCK constructs -- all declarations have to precede all executable statements.
Move the misplaced statement ahead of the first executable statement.