使用F2PY从Python处理Fortran字符数组

使用F2PY从Python处理Fortran字符数组,python,numpy,fortran,Python,Numpy,Fortran,我有一个用F2PY包装的传统Fortran库。但是,我不知道如何正确地从Python中读取声明为模块数据的字符数组。数据通过,但数组的转置方式使其无法识别。如何让Numpy正确处理阵列?如果二维字符数组的顺序可以理解,我会很满意 字符数组在Fortran中声明和填充,如下所示: module plot_mod implicit none CHARACTER*4, JSP(39) ... JSP = (/ & 'SF ', 'WF ',

我有一个用F2PY包装的传统Fortran库。但是,我不知道如何正确地从Python中读取声明为模块数据的字符数组。数据通过,但数组的转置方式使其无法识别。如何让Numpy正确处理阵列?如果二维字符数组的顺序可以理解,我会很满意

字符数组在Fortran中声明和填充,如下所示:

module plot_mod
    implicit none

    CHARACTER*4, JSP(39)

    ...

    JSP = (/ &
      'SF ',   'WF ',   'GF ',   'AF ',   'RF ',   'SS ',   'NF ', &
      'YC ',   'IC ',   'ES ',   'LP ',   'JP ',   'SP ',   'WP ', &
      'PP ',   'DF ',   'RW ',   'RC ',   'WH ',   'MH ',   'BM ', &
      'RA ',   'WA ',   'PB ',   'GC ',   'AS ',   'CW ',   'WO ', &
      'WJ ',   'LL ',   'WB ',   'KP ',   'PY ',   'DG ',   'HT ', &
      'CH ',   'WI ',   '   ',   'OT '/)

end module plot_mod
在Python 2.7(numpy的早期版本)中,我可以做到以下几点:

x = numpy.frombuffer(fvslib.plot_mod.jsp.data, numpy.dtype('a4'))
但是现在Python(3.4.4)和Numpy(1.10.4)引发了一个错误,
BufferError:memoryview:底层缓冲区不是C连续的

我知道我应该能够让Numpy通过重塑或使用步幅技巧来处理这个问题,但我似乎无法理解。数组被报告为F-连续,因此至少这看起来是正确的

如果我只是简单地打印阵列,它如下所示:

array([[b'S', b' ', b' ', b'L'],
   [b'F', b'L', b' ', b' '],
   [b' ', b'P', b'B', b' '],
   [b' ', b' ', b'M', b'W'],
   [b'W', b' ', b' ', b'B'],
   [b'F', b'J', b' ', b' '],
   [b' ', b'P', b'R', b' '],
   [b' ', b' ', b'A', b'K'],
   [b'G', b' ', b' ', b'P'],
   [b'F', b'S', b' ', b' '],
   [b' ', b'P', b'W', b' '],
   [b' ', b' ', b'A', b'P'],
   [b'A', b' ', b' ', b'Y'],
   [b'F', b'W', b' ', b' '],
   [b' ', b'P', b'P', b' '],
   [b' ', b' ', b'B', b'D'],
   [b'R', b' ', b' ', b'G'],
   [b'F', b'P', b' ', b' '],
   [b' ', b'P', b'G', b' '],
   [b' ', b' ', b'C', b'H'],
   [b'S', b' ', b' ', b'T'],
   [b'S', b'D', b' ', b' '],
   [b' ', b'F', b'A', b' '],
   [b' ', b' ', b'S', b'C'],
   [b'N', b' ', b' ', b'H'],
   [b'F', b'R', b' ', b' '],
   [b' ', b'W', b'C', b' '],
   [b' ', b' ', b'W', b'W'],
   [b'Y', b' ', b' ', b'I'],
   [b'C', b'R', b' ', b' '],
   [b' ', b'C', b'W', b' '],
   [b' ', b' ', b'O', b' '],
   [b'I', b' ', b' ', b' '],
   [b'C', b'W', b' ', b' '],
   [b' ', b'H', b'W', b' '],
   [b' ', b' ', b'J', b'O'],
   [b'E', b' ', b' ', b'T'],
   [b'S', b'M', b' ', b' '],
   [b' ', b'H', b'L', b' ']],
  dtype='|S1')
[['SF ']
, ['WF ']
, ['GF ']
, ['AF ']
, ['RF ']
, ['SS ']
, ['NF ']
, ['YC ']
, ['IC ']
, ['ES ']
, ['LP ']
, ['JP ']
, ['SP ']
, ['WP ']
, ['PP ']
, ['DF ']
, ['RW ']
, ['RC ']
, ['WH ']
, ['MH ']
, ['BM ']
, ['RA ']
, ['WA ']
, ['PB ']
, ['GC ']
, ['AS ']
, ['CW ']
, ['WO ']
, ['WJ ']
, ['LL ']
, ['WB ']
, ['KP ']
, ['PY ']
, ['DG ']
, ['HT ']
, ['CH ']
, ['WI ']
, ['   ']
, ['OT ']]
我想要一个这样的数组:

array([[b'S', b' ', b' ', b'L'],
   [b'F', b'L', b' ', b' '],
   [b' ', b'P', b'B', b' '],
   [b' ', b' ', b'M', b'W'],
   [b'W', b' ', b' ', b'B'],
   [b'F', b'J', b' ', b' '],
   [b' ', b'P', b'R', b' '],
   [b' ', b' ', b'A', b'K'],
   [b'G', b' ', b' ', b'P'],
   [b'F', b'S', b' ', b' '],
   [b' ', b'P', b'W', b' '],
   [b' ', b' ', b'A', b'P'],
   [b'A', b' ', b' ', b'Y'],
   [b'F', b'W', b' ', b' '],
   [b' ', b'P', b'P', b' '],
   [b' ', b' ', b'B', b'D'],
   [b'R', b' ', b' ', b'G'],
   [b'F', b'P', b' ', b' '],
   [b' ', b'P', b'G', b' '],
   [b' ', b' ', b'C', b'H'],
   [b'S', b' ', b' ', b'T'],
   [b'S', b'D', b' ', b' '],
   [b' ', b'F', b'A', b' '],
   [b' ', b' ', b'S', b'C'],
   [b'N', b' ', b' ', b'H'],
   [b'F', b'R', b' ', b' '],
   [b' ', b'W', b'C', b' '],
   [b' ', b' ', b'W', b'W'],
   [b'Y', b' ', b' ', b'I'],
   [b'C', b'R', b' ', b' '],
   [b' ', b'C', b'W', b' '],
   [b' ', b' ', b'O', b' '],
   [b'I', b' ', b' ', b' '],
   [b'C', b'W', b' ', b' '],
   [b' ', b'H', b'W', b' '],
   [b' ', b' ', b'J', b'O'],
   [b'E', b' ', b' ', b'T'],
   [b'S', b'M', b' ', b' '],
   [b' ', b'H', b'L', b' ']],
  dtype='|S1')
[['SF ']
, ['WF ']
, ['GF ']
, ['AF ']
, ['RF ']
, ['SS ']
, ['NF ']
, ['YC ']
, ['IC ']
, ['ES ']
, ['LP ']
, ['JP ']
, ['SP ']
, ['WP ']
, ['PP ']
, ['DF ']
, ['RW ']
, ['RC ']
, ['WH ']
, ['MH ']
, ['BM ']
, ['RA ']
, ['WA ']
, ['PB ']
, ['GC ']
, ['AS ']
, ['CW ']
, ['WO ']
, ['WJ ']
, ['LL ']
, ['WB ']
, ['KP ']
, ['PY ']
, ['DG ']
, ['HT ']
, ['CH ']
, ['WI ']
, ['   ']
, ['OT ']]

我没有尝试在您的模块上运行f2py,但是如果我将您显示的数组定义为:

In [11]: s = array([[b'S', b' ', b' ', b'L'],
    ...:    [b'F', b'L', b' ', b' '],
    ...:    [b' ', b'P', b'B', b' '],
    ...:    [b' ', b' ', b'M', b'W'],
    ...:    [b'W', b' ', b' ', b'B'],
    ...:    [b'F', b'J', b' ', b' '],
    ...:    [b' ', b'P', b'R', b' '],
    ...:    [b' ', b' ', b'A', b'K'],
    ...:    [b'G', b' ', b' ', b'P'],
    ...:    [b'F', b'S', b' ', b' '],
    ...:    [b' ', b'P', b'W', b' '],
    ...:    [b' ', b' ', b'A', b'P'],
    ...:    [b'A', b' ', b' ', b'Y'],
    ...:    [b'F', b'W', b' ', b' '],
    ...:    [b' ', b'P', b'P', b' '],
    ...:    [b' ', b' ', b'B', b'D'],
    ...:    [b'R', b' ', b' ', b'G'],
    ...:    [b'F', b'P', b' ', b' '],
    ...:    [b' ', b'P', b'G', b' '],
    ...:    [b' ', b' ', b'C', b'H'],
    ...:    [b'S', b' ', b' ', b'T'],
    ...:    [b'S', b'D', b' ', b' '],
    ...:    [b' ', b'F', b'A', b' '],
    ...:    [b' ', b' ', b'S', b'C'],
    ...:    [b'N', b' ', b' ', b'H'],
    ...:    [b'F', b'R', b' ', b' '],
    ...:    [b' ', b'W', b'C', b' '],
    ...:    [b' ', b' ', b'W', b'W'],
    ...:    [b'Y', b' ', b' ', b'I'],
    ...:    [b'C', b'R', b' ', b' '],
    ...:    [b' ', b'C', b'W', b' '],
    ...:    [b' ', b' ', b'O', b' '],
    ...:    [b'I', b' ', b' ', b' '],
    ...:    [b'C', b'W', b' ', b' '],
    ...:    [b' ', b'H', b'W', b' '],
    ...:    [b' ', b' ', b'J', b'O'],
    ...:    [b'E', b' ', b' ', b'T'],
    ...:    [b'S', b'M', b' ', b' '],
    ...:    [b' ', b'H', b'L', b' ']],
    ...:   dtype='|S1')
我可以得到一个数组,它看起来像您想要的:

In [12]: s.T.reshape(-1, 4).view('S4')
Out[12]: 
array([[b'SF  '],
       [b'WF  '],
       [b'GF  '],
       [b'AF  '],
       [b'RF  '],
       [b'SS  '],
       [b'NF  '],
       [b'YC  '],
       [b'IC  '],
       [b'ES  '],
       [b'LP  '],
       [b'JP  '],
       [b'SP  '],
       [b'WP  '],
       [b'PP  '],
       [b'DF  '],
       [b'RW  '],
       [b'RC  '],
       [b'WH  '],
       [b'MH  '],
       [b'BM  '],
       [b'RA  '],
       [b'WA  '],
       [b'PB  '],
       [b'GC  '],
       [b'AS  '],
       [b'CW  '],
       [b'WO  '],
       [b'WJ  '],
       [b'LL  '],
       [b'WB  '],
       [b'KP  '],
       [b'PY  '],
       [b'DG  '],
       [b'HT  '],
       [b'CH  '],
       [b'WI  '],
       [b'    '],
       [b'OT  ']], 
      dtype='|S4')
请注意,数据类型为
'S4'
,以匹配Fortran数组的声明大小

这个结果留下了一个微不足道的第二维度,因此您可能希望将其转换为一维数组,例如

In [22]: s.T.reshape(-1, 4).view('S4')[:,0]
Out[22]: 
array([b'SF  ', b'WF  ', b'GF  ', b'AF  ', b'RF  ', b'SS  ', b'NF  ',
       b'YC  ', b'IC  ', b'ES  ', b'LP  ', b'JP  ', b'SP  ', b'WP  ',
       b'PP  ', b'DF  ', b'RW  ', b'RC  ', b'WH  ', b'MH  ', b'BM  ',
       b'RA  ', b'WA  ', b'PB  ', b'GC  ', b'AS  ', b'CW  ', b'WO  ',
       b'WJ  ', b'LL  ', b'WB  ', b'KP  ', b'PY  ', b'DG  ', b'HT  ',
       b'CH  ', b'WI  ', b'    ', b'OT  '], 
      dtype='|S4')

为完整起见,我将包括此替代解决方案。与@Warren Weckesser的结果相同,但需要额外导入

from numpy.lib import stride_tricks

spp = stride_tricks.as_strided(jsp, strides=(jsp.shape[1],1))

# View as S4 and strip whitespace
spp = np.char.strip(spp.view('S4'))

完美的转置是我丢失的钥匙。发布后不久,我就知道了如何使用stride_tricks模块,但这比IMHO好得多。