Fortran Coder

标题: Python使用Ctypes调用fortran的dll问题请教 [打印本页]

作者: Labradog    时间: 2016-9-7 00:08
标题: Python使用Ctypes调用fortran的dll问题请教
本帖最后由 Labradog 于 2016-9-7 12:46 编辑

各位好,前段时间发过一个python利用f2py调用fortran的帖子,下面回复的@pasuka兄弟建议我用Ctypes或是cffi,后来自己了解了一下,综合对比了一下,确实Ctypes更好用。现在有一个小问题,想跟各位请教一下。Fortran代码如下。

[Fortran] 纯文本查看 复制代码
!*****************************************************
!   随机数模块:
!      通过重载分别定义针对数组以及int的过程
!
!*****************************************************
module rand_m
    implicit none

    interface randi            ! 过程重载
        module procedure randi_ar   ! 数组
        module procedure randi_in   ! int
    end interface
    contains
    !****************************************
        subroutine randi_ar(int_min,int_max,rand_arr)
        ! 输入:下界,上界,随机数变量--数组
        ! 输出:随机数变量--数组
            implicit none
            
            integer,intent(in)::int_min
            integer,intent(in)::int_max
            integer,intent(out),dimension(:)::rand_arr

            ! 局部变量
            real,allocatable,dimension(:)::temp

            if (.not. allocated(temp)) allocate(temp(size(rand_arr)))

            call random_seed()
            call random_number(temp)
            rand_arr=abs(int_max-int_min)*temp+min(int_min,int_max)
            ! 返回rand_arr:随机数组            
        end subroutine randi_ar

        subroutine randi_in(int_min,int_max,rand_int)
        ! 输入:下界,上界,随机数变量--int
        ! 输出:随机数变量--int
            implicit none

            integer,intent(in)::int_min
            integer,intent(in)::int_max
            integer,intent(out)::rand_int

            ! 局部变量
            real::temp

            call random_seed()
            call random_number(temp)
            rand_int=abs(int_max-int_min)*temp+min(int_min,int_max)
            ! 返回rand_int:随机数--int   
        end subroutine randi_in
end module rand_m


module OM_module
use,intrinsic::iso_c_binding
use rand_m
implicit none
contains
    subroutine rand_nucle(arr,nucle_num,n1,n2)
    !dec$ attributes dllexport,decorate,alias:"rand_nucle" :: rand_nucle

        implicit none
            integer(kind=c_int),intent(in),value::n1,n2,nucle_num
        integer(kind=c_int),intent(out),dimension(n1,n2)::arr

            integer::nval=1
        integer,allocatable,dimension(:)::temp_index  ! 二维数组两个索引,不需要改动
        real::i,j

        if (.not. allocated(temp_index)) allocate(temp_index(2))    ! 二维数组两个索引,数字2不需要改动      
   
        do while (nval<=nucle_num)
            call randi(1,n1,temp_index(1))
            call randi(1,n2,temp_index(2))
               
            if (arr(temp_index(1),temp_index(2))<=0) then   ! 注意一定是小于等于,只有小于会一直执行条件语句
                call randi(1,180,arr(temp_index(1),temp_index(2)))
                nval=nval+1
            end if                                
        end do
        deallocate(temp_index)
        end subroutine rand_nucle
end module OM_module
!*****************************************************

program test
    use OM_module
    implicit none
    integer,dimension(5,5)::arr
    integer::n1,n2,n3

    arr=0

    n1=5
    n2=5
    n3=2

    write(*,*) arr
    write(*,*) "*************"

    call rand_nucle(arr,n3,n1,n2)

    write(*,*) arr

end program

代码主要是在一个全0二位数组中随机生成几个正整数。
Test之后证明Fortran代码没得问题,不管写的怎么样,反正能实现我的想法。
fortran 命令行编译dll:ifort /dll test.F90 生成test1.dll。

Python代码如下:
[Python] 纯文本查看 复制代码
#! /usr/bin/env python
#coding=utf-8
import numpy as np
from numpy.ctypeslib import load_library,ndpointer
from ctypes import *
# shape of 2d array
n1,n2 = 10,10
n3=3
# create an empty 2d array
data = np.zeros(shape=(n1,n2),dtype='int64',order='f')
flib = load_library("test1.dll","./")
flib.argtypes = [ndpointer(dtype='int64',ndim=2),c_int,c_int,c_int]
flib.rand_nucle(data.ctypes.data,n3,n1,n2)
print "*"*80
print data


从python中传入一个全0二维矩阵,运算完后返回,运行之后矩阵变成了如下图:
显然有两个数字太大了,完全不对。我在Fortran中设定的是1-180之间的正整数,在fortran中test也正常。为何python调用之后成了这个样子,百思不得其解,还请各位帮忙看看。
PS:Fcode兄弟提醒后把Python中int64改成int就OK了,我会继续想怎么让ifort默认int64。改后得到的结果在第二张图片上。


array.png (36.31 KB, 下载次数: 608)

array.png

array.png (27.64 KB, 下载次数: 608)

array.png

作者: pasuka    时间: 2016-9-7 09:59
lz确定ifort默认的integer就是int64吗?
numpy的dtype说明
http://docs.scipy.org/doc/numpy/user/basics.types.html
作者: Labradog    时间: 2016-9-7 11:30
pasuka 发表于 2016-9-7 09:59
lz确定ifort默认的integer就是int64吗?
numpy的dtype说明
http://docs.scipy.org/doc/numpy/user/basics.t ...

  擦汗。。不确定。。。怎么来看ifort默认的integer是int64还是int32之类的呢?
作者: fcode    时间: 2016-9-7 11:34
一般默认的都是 int32
作者: Labradog    时间: 2016-9-7 12:43
fcode 发表于 2016-9-7 11:34
一般默认的都是 int32

把python里int64改成int之后就可以了。。。谢谢你。
作者: Labradog    时间: 2016-9-7 12:44
pasuka 发表于 2016-9-7 09:59
lz确定ifort默认的integer就是int64吗?
numpy的dtype说明
http://docs.scipy.org/doc/numpy/user/basics.t ...

fcode兄弟给我说的,我把Python里int64改成int就ok了。这里跟你说一下,感谢你回帖。
作者: pasuka    时间: 2016-9-7 15:24
查手册呗,譬如
https://gcc.gnu.org/onlinedocs/g ... ran-Dialect-Options
-fdefault-integer-8
-finteger-4-integer-8
作者: lihu8918    时间: 2017-5-28 10:26
楼主代码里引入了iso_c_binding模块,但是子程序rand_nucle并没用使用bind(c),为什么呢?
作者: 维尼猴    时间: 2017-7-16 10:19
学习了~

正准备看f2yp,这么一说正好能比较着学习一下~
作者: 老王    时间: 2017-11-9 10:15
按照楼主的修改方法,怎么会出现问题呢。ArgumentError: argument 1: <class 'OverflowError'>: int too long to convert。已经是int类型了呀!!!
作者: lveZ    时间: 2020-7-1 14:06
谢谢博主,很有用,我有一个问题想要请教一下,在调用Fortran的DLL的时候可以直接调用主函数吗?即没有输入参数
作者: xiaobai-f2py    时间: 2024-3-22 15:26
本帖最后由 xiaobai-f2py 于 2024-3-24 20:47 编辑

谢谢楼主,请问使用ctypes是不是把必须用c语言编写被调用程序?
作者: xiaobai-f2py    时间: 2024-3-24 20:48
lveZ 发表于 2020-7-1 14:06
谢谢博主,很有用,我有一个问题想要请教一下,在调用Fortran的DLL的时候可以直接调用主函数吗?即没有输入 ...

你好,我也有同样的困扰,请问你解决了吗




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2