我有一个数值例程,我需要运行它来求解某个方程,其中包含几个嵌套的四个循环。最初,我将这个例程写入Python中,使用numba.jit实现可接受的性能。然而,对于较大的系统规模,这个方法变得非常慢,所以我一直在将例程重写为Fortran,希望能够实现加速。然而,我发现我的Fortran版本比Python中的第一个版本慢得多,比第一个版本慢了2-3倍。
我相信瓶颈是一个线性插值函数,它在每个最里面的循环上被调用。在Python实现中,我使用numpy.interp,它与numba.jit结合起来似乎非常快。在Fortran中,我编写了我自己的插值函数,它是这样的:
complex*16 function interp(x_dat, y_dat, N_dat, x)
implicit none
integer, intent(in) :: N_dat
real*8, dimension(N_dat), intent(in) :: x_dat
complex*16, dimension(N_dat), intent(in) :: y_dat
real*8, intent(in) :: x
complex*16 :: y, y1, y2
integer :: i, i1, i2, im
if(x <= x_dat(1)) then
y = y_dat(1)
else if(x >= x_dat(N_dat)) then
y = y_dat(N_dat)
else
im = MINLOC(DABS(x_dat - x), DIM=1)
if(x_dat(im) >=x ) then
i1 = im
i2 = im - 1
else
i1 = im + 1
i2 = im
end if
y1 = y_dat(i1)
y2 = y_dat(i2)
y = y1 + (x-x_dat(i1))*(y2 - y1)/(x_dat(i2) - x_dat(i1))
end if
interp = y
return
end function interp注意,我需要插值复杂的数据。如果我的诊断是正确的,这个函数比numpy.interp慢得多,因为插值必须在每个循环中调用,大大降低了整个程序的速度。
有没有人知道在Fortran中是否有实现像插值速度一样的Numpy的方法?或者,如果我的插值函数,如上面所示,在某种程度上效率很低?我还没有多少编码Fortran的经验。
谢谢!
发布于 2022-02-06 13:40:02
如果你想让我们做得比猜测更好的话,请看一下@IanBush的评论。
im = MINLOC(DABS(x_dat - x), DIM=1)这占用了您所有的时间,因为这一行是O(N)大小的x_dat,其他的都是O(1)。
如果x_dat是线性行距的,那么您可以用
im = 1 + nint((N_dat-1)*(x-x_dat(1))/(x_dat(N_dat)-x_dat(1)))或者更好的方法是跳过im,计算i1和i2
i1 = 1 + floor((N_dat-1)*(x-x_dat(1))/(x_dat(N_dat)-x_dat(1)))
i2 = i1 + 1如果x_dat不是线性行距,而是具有其他有用的属性,那么如果可能的话,您希望使用这些属性来计算im。
https://stackoverflow.com/questions/71007062
复制相似问题