Fortran Coder

查看: 20370|回复: 12
打印 上一主题 下一主题

[混编] Python使用Ctypes调用fortran的dll问题请教

[复制链接]

8

帖子

2

主题

1

精华

入门

F 币
79 元
贡献
41 点
跳转到指定楼层
楼主
发表于 2016-9-7 00:08:09 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 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, 下载次数: 607)

array.png

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

array.png
分享到:  微信微信
收藏收藏1 点赞点赞1 点踩点踩

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

沙发
发表于 2016-9-7 09:59:36 | 只看该作者
lz确定ifort默认的integer就是int64吗?
numpy的dtype说明
http://docs.scipy.org/doc/numpy/user/basics.types.html

8

帖子

2

主题

1

精华

入门

F 币
79 元
贡献
41 点
板凳
 楼主| 发表于 2016-9-7 11:30:02 | 只看该作者
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之类的呢?

2033

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1641 元
贡献
709 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

地板
发表于 2016-9-7 11:34:41 | 只看该作者
一般默认的都是 int32

8

帖子

2

主题

1

精华

入门

F 币
79 元
贡献
41 点
5#
 楼主| 发表于 2016-9-7 12:43:05 | 只看该作者
fcode 发表于 2016-9-7 11:34
一般默认的都是 int32

把python里int64改成int之后就可以了。。。谢谢你。

8

帖子

2

主题

1

精华

入门

F 币
79 元
贡献
41 点
6#
 楼主| 发表于 2016-9-7 12:44:17 | 只看该作者
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了。这里跟你说一下,感谢你回帖。

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

7#
发表于 2016-9-7 15:24:04 | 只看该作者
查手册呗,譬如
https://gcc.gnu.org/onlinedocs/g ... ran-Dialect-Options
-fdefault-integer-8
-finteger-4-integer-8

10

帖子

3

主题

0

精华

入门

F 币
24 元
贡献
33 点
8#
发表于 2017-5-28 10:26:15 | 只看该作者
楼主代码里引入了iso_c_binding模块,但是子程序rand_nucle并没用使用bind(c),为什么呢?

47

帖子

3

主题

0

精华

大师

F 币
1634 元
贡献
119 点

规矩勋章

9#
发表于 2017-7-16 10:19:10 | 只看该作者
学习了~

正准备看f2yp,这么一说正好能比较着学习一下~

1

帖子

0

主题

0

精华

新人

F 币
18 元
贡献
2 点
10#
发表于 2017-11-9 10:15:48 | 只看该作者
按照楼主的修改方法,怎么会出现问题呢。ArgumentError: argument 1: <class 'OverflowError'>: int too long to convert。已经是int类型了呀!!!
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-12-25 00:06

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表