简体   繁体   English

使用f2py将numpy字符串格式数组传递给fortran

[英]Passing numpy string-format arrays to fortran using f2py

My aim is to print the 2nd string from a python numpy array in fortran, but I only ever get the first character printed, and it's not necessarily the right string either. 我的目标是从fortran中的python numpy数组中打印第二个字符串,但是我只打印了第一个字符,并且它也不一定是正确的字符串。

Can anyone tell me what the correct way to pass full string arrays to fortran? 任何人都可以告诉我将完整的字符串数组传递给fortran的正确方法是什么?

The code is as follows: 代码如下:

testpy.py testpy.py

import numpy as np
import testa4

strvar = np.asarray(['aa','bb','cc'], dtype = np.dtype('a2'))
testa4.testa4(strvar)

testa4.f90 testa4.f90

subroutine testa4(strvar)
implicit none

character(len=2), intent(in) :: strvar(3)
!character*2 does not work here - why?

print *, strvar(2)

end subroutine testa4

Compiled with 编译

f2py -c -m testa4 testa4.f90

Output of above code 输出上述代码

c

Desired output 期望的输出

bb

I don't know how to do that using f2py . 我不知道如何使用f2py做到这f2py But it can be done with ctypes . 但它可以用ctypes完成。 You get an array of characters, but you can convert it to a string very easily. 你得到一个字符数组,但你可以很容易地将它转换为字符串。

subroutine testa4(strvar) bind(C, name='testa4')
  use iso_c_binding
  implicit none

  character(len=1,kind=c_char), intent(in) :: strvar(2,3)

  print *, strvar(:,2)

end subroutine testa4

compile: gfortran -shared -fPIC testa4.f90 -o testa4.so 编译: gfortran -shared -fPIC testa4.f90 -o testa4.so

import numpy as np
import ctypes

testa4 = ctypes.CDLL("./testa4.so")

strvar = np.asarray(['aa','bb','cc'], dtype = np.dtype('a2'))
strvar_p = ctypes.c_void_p(strvar.ctypes.data)

testa4.testa4(strvar_p)

run: 跑:

> python testpy.f90 
 bb

Per the documentation , f2py likes string arrays to be passed with dtype='c' (ie, '|S1'). 根据文档 ,f2py喜欢使用dtype ='c'传递的字符串数组(即'| S1')。 This gets you part of the way there, although there are some oddities with array shape going on behind the scenes (eg, in a lot of my tests I found that fortran would keep the 2 character length, but interpret the 6 characters as being indicative of a 2x6 array, so I'd get random memory back in the output). 这会让你成为那里的一部分,虽然在幕后有一些奇怪的阵列形状(例如,在我的很多测试中,我发现fortran会保留2个字符的长度,但是将6个字符解释为指示一个2x6阵列,所以我会在输出中得到随机存储器)。 This (as far as I could tell), requires that you treat the Fortran array as a 2D character array (as opposed to a 1D "string" array). 这(据我所知),要求您将Fortran数组视为2D字符数组(而不是1D“字符串”数组)。 Unfortunately, I couldn't get it to take assumed shape and ended up passing the number of strings in as an argument. 不幸的是,我无法让它采取假定的形状,并最终将字符串的数量作为参数传递。

I'm pretty sure I'm missing something fairly obvious, but this should work for the time being. 我很确定我错过了一些相当明显的东西,但这应该暂时有效。 As to why CHARACTER*2 doesn't work ... I honestly have no idea. 至于为什么CHARACTER * 2不起作用......我真的不知道。

MODULE char_test

CONTAINS

SUBROUTINE print_strings(strings, n_strs)
    IMPLICIT NONE

    ! Inputs
    INTEGER, INTENT(IN) :: n_strs
    CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings

!f2py INTEGER, INTENT(IN) :: n_strs
!f2py CHARACTER, INTENT(IN), DIMENSION(2,n_strs) :: strings

    ! Misc.
    INTEGER*4 :: j


    DO j=1, n_strs
        WRITE(*,*) strings(:,j)
    END DO

END SUBROUTINE print_strings

END MODULE char_test

----------------

import numpy as np
import char_test as ct

strings = np.array(['aa', 'bb', 'cc'], dtype='c').T
ct.char_test.print_strings(strings, strings.shape[1])

strings = np.array(['ab', 'cd', 'ef'], dtype='c').T
ct.char_test.print_strings(strings, strings.shape[1]) 

-->python run_char_test.py
 aa
 bb
 cc
 ab
 cd
 ef

Not really an answer but too long to comment: maybe this helps.. 不是一个答案,但是评论太久了:也许这有助于......

in your first case what gets passed in to fortran is for some reason the first character of each string: 在你的第一种情况下,传递给fortran的是由于某种原因每个字符串的第一个字符:

'abc'

which in fortran ends up in the length 2 arrays as 'ab' , 'c'. 在fortran中,在长度为2的数组中最终为'ab','c'。 If you work strictly with length one string arrays all is well, I suppose. 如果你严格地使用长度一个字符串阵列一切都很好,我想。 Unfortunately you cant fake the system and split into a single character array in python ['a','a','b','b'.. - it throws an error if the array lengths don't match. 不幸的是你不能伪造系统并在python中分成单个字符数组['a','a','b','b'.. - 如果数组长度不匹配则抛出错误。

On your second question, if you declare with the 关于你的第二个问题,如果你宣布

  character*2

notation, it actually works to simply pass a regular python string list: 它实际上只是传递一个常规的python字符串列表:

  testa4.testa4(['aa','bb','cc'])

(and now throws an error if you try the numpy string array.). (如果你尝试numpy字符串数组,现在会抛出一个错误。)。 The strings must be the exact correct length or it throws an error here as well. 字符串必须是正确的正确长度,否则它也会引发错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM