【问题标题】:Can I use libraries like numpy and scipy in fortran?我可以在 fortran 中使用像 numpy 和 scipy 这样的库吗?
【发布时间】:2018-07-27 20:28:45
【问题描述】:

我试图通过将一堆嵌套循环移植到 fortran 并将它们作为子例程调用来加速我的 python 代码。

但是我的很多循环都调用了 numpy,以及来自 scipy 的特殊函数,例如 bessel 函数。

在我尝试使用 fortran 之前,我想知道是否可以将 scipy 和 numpy 导入我的 fortran 子例程并调用这些模块以实现 bessel 函数?

否则我是否必须在 fortran 中创建 bessel 函数才能使用它?

理想情况下,我会创建某种子程序来优化下面的代码。这只是我整个项目的一个简单介绍,让您了解我想要完成的工作。

我知道我应该实施其他做法来提高速度,但现在我正在研究在我的主要 python 程序中调用 fortran 子例程的好处。

    for m in range(self.MaxNum_Eigen):
        #looping throught the eigenvalues for the given maximum number of eigenvalues allotted
        bm = self.beta[m]


        #not sure
        #*note: rprime = r. BUT tprime ~= t.

        #K is a list of 31 elements for this particular case

        K = (bm / math.sqrt( (self.H2**2) + (bm**2) ))*(math.sqrt(2) / self.b)*((scipy.special.jv(0, bm * self.r))/ (scipy.special.jv(0, bm * self.b))) # Kernel, K0(bm, r).

        #initial condition
        F = [37] * (self.n1)

        # Integral transform of the initial condition
        #Fbar = (np.trapz(self.r,self.r*K*F))

        '''
            matlab syntax trapz(X,Y), x ethier spacing or vector
            matlab:     trapz(r,r.*K.*F)                trapz(X,Y)
            python:     np.trapz(self.r*K*F, self.r)    trapz(Y,X)

        '''

        #*(np.trapz(self.r,self.r*K*F))
        Fbar = np.ones((self.n1,self.n2))*(np.trapz(self.r*K*F, self.r))

        #steady state condition: integral is in steady state
        SS = np.zeros((sz[0],sz[1]))

        coeff = 5000000*math.exp(-(10**3)) #defining value outside of loop with higher precision

        for i in range(sz[0]):
            for j in range(sz[1]):

                '''
                    matlab reshape(Array, size1, size2) takes multiple arguments the item its resizeing and the new desired shape

                    create self variables and so we are not re-initializing them over and over agaian?

                    using generators? How to use generators

                '''
                s = np.reshape(tau[i,j,:],(1,n3))


                # will be used for rprime and tprime in Ozisik solution.
                [RR,TT] = np.meshgrid(self.r,s)



                '''
                    ##### ERROR DUE TO ROUNDING OF HEAT SOURCE ####

                    error in rounding  5000000*math.exp(-(10**3)) becomes zero

                    #log10(e−10000)=−10000∗(0.4342944819)=−4342.944819

                    #e−1000=10−4342.944819=10−4343100.05518=1.13548386531×10−4343

                '''

                #g = 5000000*math.exp(-(10**3)) #*(RR - self.c*TT)**2) #[W / m^2] heat source.
                g = coeff * (RR - self.c*TT)**2


                K = (bm/math.sqrt(self.H2**2 + bm**2))*(math.sqrt(2)/self.b)*((scipy.special.jv(0,bm*RR))/(scipy.special.jv(0,bm*self.b)))

                #integral transform of heat source
                gbar = np.trapz(RR*K*g, self.r, 2) #trapz(Y,X,dx (spacing) )
                gbar = gbar.transpose()



                #boundary condition. BE SURE TO WRITE IN TERMS OF s!!!
                f2 = self.h2 * 37

                A = (self.alpha/self.k)*gbar + ((self.alpha*self.b)/self.k2)*((bm/math.sqrt(self.H2**2 + bm**2))*(math.sqrt(2)/self.b)*((scipy.special.jv(0,bm*self.b))/(scipy.special.jv(0,bm*self.b))))*f2
                #A is essentially a constant is this correct all the time?
                #What does A represent

                SS[i, j] = np.trapz(np.exp( (-self.alpha*bm**2)*(T[i,j] - s) )*A, s)

        #INSIDE M loop
        K = (bm / math.sqrt((self.H2 ** 2) + (bm ** 2)))*(math.sqrt(2) /self.b)*((scipy.special.jv(0, bm * R))/ (scipy.special.jv(0, bm * self.b)))


        U[:,:, m] = np.exp(-self.alpha * bm ** 2 * T)* K* Fbar + K* SS

        #print(['Eigenvalue ' num2str(m) ', found at time ' num2str(toc) ' seconds'])

【问题讨论】:

  • 很多 Numpy 函数已经在 C 中实现了。如果你使用循环来做某事,那通常意味着你在矩阵运算中做错了
  • 一般来说,您的问题的答案是“是的,您需要在 fortran 中创建函数才能在 fortran 中使用它”。但是,我不认为你在问正确的问题。正如@cricket_007 所指出的,如果您使用循环来使用 Numpy 或 Scipy 做某事,那么您可能做错了什么并且没有充分利用这些软件包。 Numpy 和 Scipy 中的大多数操作都可以在整个数组上执行,而无需循环。也许你可以展示一个循环的小例子,并寻求帮助矢量化你的循环。
  • @cricket_007 在 C 或 Fortran 中。两者都可以从 Fortran 轻松调用。
  • 不熟悉 Scipy 中的 Bessel 函数,但使用 .j0()(而不是 .jv())可能会加快代码速度? docs.scipy.org/doc/scipy/reference/generated/… 最近的 Fortran 编译器可能内置了 Bessel 函数... fortranwiki.org/fortran/show/Bessel+function gcc.gnu.org/onlinedocs/gfortran/BESSEL_005fJN.html
  • Bessel 函数被添加到 2008 年(我认为)语言标准中的 Fortran 内部例程中,所有主要编译器以前都有实现,因此无需移植。

标签: python numpy scipy fortran f2py


【解决方案1】:

cmets 中给出的答案汇编

针对我的代码的答案: 正如 vorticity 提到的,我的代码本身并没有最大限度地使用 numpy 和 scipy 包。

关于 Bessel,函数 'royvib' 提到使用 scipy 中的 .jo 而不是 .jv。调用特殊的 Bessel 函数 jv。计算成本要高得多,特别是因为我知道我会为我的许多声明使用零阶贝塞尔函数,从 jv -> j0 解决的微小变化加快了进程。

此外,我在循环外部声明了变量,以防止昂贵的调用来搜索我的适当函数。下面的例子。

之前

for i in range(SomeLength):
    some_var = scipy.special.jv(1,coeff)

之后

Bessel = scipy.special.jv
for i in range(SomeLength):
    some_var = Bessel(1,coeff)

存储函数通过不使用点 ('.') 命令在每个循环中查看库来节省时间。但是请记住,这确实使 python 的可读性降低,这是我选择在 python 中做这个项目的主要原因。我没有从我的流程中删除此步骤的确切时间。

Fortran 特定: 因为我能够改进我的 python 代码,所以我没有走这条路,因为缺乏细节,但“高性能标记”所说的一般答案是,是的,有一些库可以在 Fortran 中处理 Bessel 函数。

如果我将我的代码移植到 Fortran 或使用 f2py 混合 Fortran 和 python,我将相应地更新此答案。

【讨论】:

  • 不仅仅是库,Bessel 函数是内在函数,是内置的,由 Fortran 编译器直接处理。
  • 正如@VladimirF 所说,Bessel 函数是 Fortran 2008 标准的固有部分,并且已经在 Absoft、Cray、GNU、Intel 和 PGI Fortran 编译器中实现。请相应地更正您的答案,因为它可能会误导新手 Fortran 程序员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-03-09
  • 2011-03-11
  • 2013-02-08
  • 1970-01-01
  • 2017-11-08
  • 2014-06-10
  • 1970-01-01
相关资源
最近更新 更多