我正在使用fortran而我正在尝试使用矩阵的导数,其元素是函数。
program derivada_matrix
integer, parameter :: matrix_size = 5
integer :: i,j
real(8) :: time = 1.0
real(8),dimension (matrix_size, matrix_size) :: W
real(8),dimension (matrix_size, matrix_size) :: dW
call potent(time,W)
do i = 1, matrix_size
do j=1, matrix_size
call Derivada(time,W(i,j),dW(i,j))
end do
end do
print*, 'matrix'
print*, W
print*, 'derivada', dW
end program
Subroutine Derivada (x1,F,D)
implicit none
Real*8 :: x1
Real*8 :: h= 1.0E-6
integer, parameter :: matrix_size = 5
real*8 :: D,F
external F
D = (1.0*F(x1-2*h) - 8.0*F(x1-h) + 8.0*F(x1+h) - 1.0*F(x1+2*h))/(12.0*h)
return
End subroutine Derivada
subroutine potent(T,W)
implicit none
integer, parameter :: matrix_size = 5
real(8),dimension(matrix_size,matrix_size) :: W
Real(8):: T
integer :: i,j
do i = 1, matrix_size
do j=i,matrix_size
W(i,j) = 0.0
W(j,i) = W(i,j)
end do
W(i,i) = cos(T)
end do
RETURN
END subroutine potent
基本上,第一个子程序在主对角线上创建一个带有函数(余弦)的测试矩阵,在其他地方创建零,并且它应该推导出第二个子程序。 这是我收到的错误/警告信息
call Derivada(time,W(i,j),dW(i,j))
1
Warning: Expected a procedure for argument ‘f’ at (1)
我收到的错误/警告信息是在第二个电话中。我想因为当我创建W矩阵时,它将其属性作为函数丢失,然后我不能在第二次调用中用作派生每个元素的参数。 怎么能改善呢? 如何创建一个程序/函数子程序,它的输入是这样的矩阵,它的输出将是它的衍生物???
由于
答案 0 :(得分:0)
代码没有按照您的想法行事。 W
只是一系列实物。您只需填写T
点评估的cos条目。它不是一系列函数。
这是一种更现代化的方法,可以满足您的需求。它不使用extern函数,而是使用过程指针并将它们包装在派生类型中,以便您可以创建它们的数组。然后你指向你想要它的衍生物的函数。
这种方法的局限性在于您必须遵守接口,在这种情况下,它只适用于接受一个双参数的函数。您可以通过多种方式扩展它,例如使用可选参数,将它们包装在派生类型中,或使用多个接口,但这取决于您。
module deriv
use, intrinsic :: iso_fortran_env, only: dp => real64
implicit none
! Wrapper for a procedure pointer so we can make an array of them
type ptr_wrapper
procedure(f), nopass, pointer :: func
end type ptr_wrapper
! Use an interface for the function rather than "extern" functions
! Change the interface to whatever you want. You could take multiple reals, integers, etc
abstract interface
pure function f(x1)
import
real(dp), intent(in) :: x1
real(dp) :: f
end function f
end interface
contains
function derivada(x1, fx) result(d)
implicit none
real(dp), intent(in) :: x1
procedure(f), pointer :: fx
real(dp) :: d
real(dp) :: h = 1.0E-6
d = (1.0*fx(x1-2*h) - 8.0*fx(x1-h) + 8.0*fx(x1+h) - 1.0*fx(x1+2*h))/(12.0*h)
end function derivada
pure function test_func(x1)
real(dp), intent(in) :: x1
real(dp) test_func
test_func = 2d0 * x1
end function test_func
pure function test_func2(x1)
real(dp), intent(in) :: x1
real(dp) test_func2
test_func2 = x1**2
end function test_func2
end module deriv
program derivada_matrix
use, intrinsic :: iso_fortran_env, only: dp => real64
use deriv
implicit none
integer i, j
real(dp) :: dx
type(ptr_wrapper) :: w(2,2)
!Point to the function that you want each index to point to
w(1,1)%func => test_func
w(1,2)%func => test_func2
! Pointing to the generic function wasn't working so I had to point to the specific double value trig functions
w(2,1)%func => dcos
w(2,2)%func => dsin
do i = 1, 2
do j = 1, 2
dx = derivada(1d0, w(i,j)%func)
print *, dx
end do
end do
end program derivada_matrix
它在x = 1.0
时打印出这些函数的导数 2.00000000000000
2.00000000011102
-0.841470984776962
0.540302305853706