2017-01-26 4 views
2

После некоторого копания в Интернете и пробной ошибки, мне все еще интересно, как передавать массивы строк из Python в Fortran с помощью f2py.Как передать массив строк в подпрограмму Fortran с помощью f2py

У меня есть Fortran подпрограмму в string.f90 как:

SUBROUTINE FOO(A) 
    CHARACTER*5,dimension(10),intent(inout):: A 
    PRINT*, "A=",A 
    END 

Тогда я бегу f2py -m mystring -c string.f90. Компиляция прошла успешно.

Питон сессия в test.py:

import mystring 
import numpy as np 
nobstot=10 
xstring=np.empty(nobstot,dtype='S5') 
xstring[0]="ABCDE" 
mystring.foo(xstring) 

Run python test.py, у меня есть сообщение об ошибке:

1-th dimension must be 5 but got 0 (not defined). 
Traceback (most recent call last) : 
File "test.py", line 6, in <module> 
mystring.foo(xstring) 
mystring.error: failed in converting 1st argument `a' of mystring.foo to C/Fortran array 

В f2py компиляции этапе были вынесено gfortran и GCC компилятор.

После >>> print mystring.foo.__doc__, был:

foo(a) 
Wrapper for ``foo``. 
Parameters 
--------- 
a : in/output rank-2 array('S') with bounds (10,5) 

Итак, я попытался test.py как:

import mystring 
import numpy as np 
nobstot=10 
xstring=np.empty((nobstot,5),dtype='S1') 
print xstring.shape 
xstring[0]="ABCDE" 
mystring.foo(xstring) 

Затем запустите python test.py, сообщение об ошибке было:

Traceback (most recent call last): 
File "test.py", line 7, in <module> 
mystring.foo(xstring) 
ValueError: failed to initialize intent(inout) array -- input 'S' not compatible to 'c' 
+0

Не добавлять приветствия к вашему после. Ваше имя уже помещено под ваш вопрос рядом с вашим значком автоматически. –

+0

@ Vladimire F. Got it. Большое спасибо за вашу помощь. –

ответ

2

Прежде всего, чтобы передать массив строк Fortran в Python, вы должны создать массив символов с формой (<number of strings>, <string length>), заполнить его содержимое и передать массив char в f2py сгенерированную функцию. Используя ваш пример:

xstring = np.empty((nobstot, 5), dtype='c') 
xstring[0] = "ABCDE" 
xstring[1] = "FGHIJ" 
mystring.foo(xstring) 

Для того, чтобы это работало, вам необходимо изменить свой код Fortran тоже:

subroutine foo(A) 
character*5, dimension(10), intent(in) :: A 
print*, "A(1)=",A(1) 
print*, "A(2)=",A(2) 
end 

Обратите внимание, что intent(inout) заменяется intent(in). Это связано с тем, что строки в Python, а также строки в массивах numpy строк неизменны, но в Fortran они могут и не быть. В результате макет памяти строк Python не может просто передаваться функциям Fortran, и пользователь должен реорганизовать строковые данные, как описано выше.

Во-вторых, если ваш код Fortran изменяет строки, как предполагает использование intent(inout), вам необходимо объявить такие строковые аргументы, как intent(in, out), например, с помощью директивы f2py.Далее следует полный пример:

subroutine foo(A) 
character*5, dimension(10), intent(inout) :: A 
!f2py intent(in, out) A 
print*, "A(1)=",A(1) 
print*, "A(2)=",A(2) 
A(1)="QWERT" 
end 

F2py вызов:

f2py -m mystring -c string.f90 

Python тестовый скрипт:

import mystring 
import numpy as np 
nobstot = 10 
xstring = np.empty((nobstot, 5), dtype='c') 
xstring[0] = "ABCDE" 
xstring[1] = "FGHIJ" 
xstring = mystring.foo(xstring) 
print("xstring[0]=",string[0].tostring()) 
print("xstring[1]=",string[1].tostring()) 

Консоль вывода:

A(1)=ABCDE 
A(2)=FGHIJ 
xstring[0]= QWERT 
xstring[1]= FGHIJ 
+0

Я не понимаю, почему код Fortran должен быть изменен так, как вы показываете. (Оставляя в стороне опечатку с синтаксисом-ошибкой.) –

+0

Как правило, намерение '! F2py (in, out) A' не требуется, потому что вместо этого используется форматирование' inout ''' автоматически. Почему вы говорите, что это необходимо здесь? –

+0

Настоящая причина, по которой требуется '! F2py intent (in, out)', заключается в том, что поддержка f2py для строковых массивов является неполной. после активной разработки f2py были введены массивы строк numpy. При завершении поддержки строкового массива использование массивов строк numpy позволит решить эту проблему навсегда. До сих пор все еще можно использовать f2py, но с вышеупомянутыми ограничениями (используйте массивы numpy char, а не numpy string array). – Pearu

0

Общаясь строку и от fortran немного сложно.

С помощью этой линии вы establisted практического двумерный характера массива 10 * 5

CHARACTER*5,dimension(10),intent(inout):: A 

попробуйте изменить его на

CHARACTER*10,intent(inout):: A 

, что делает его одномерный массив из 10 символов. Если это работает, но вывод - мусор, проверьте, совпадают ли оба формата символов (ascii/multibyte или unicode).

+0

Большое спасибо. Да, когда он объявлен как скаляр строки, скрипт python завершается нормально. И, к счастью, выход выглядит нормально, как ожидалось. Для того, чтобы быть сейчас, я буду придерживаться вашего предложения для моей цели. Если у меня есть новая информация или более простое решение, которое можно использовать в реальных случаях, я обновлю его здесь. Для того, чтобы быть сейчас, я подожду какое-то время, чтобы увидеть, есть ли другие предложения, прежде чем я выберу ваш ответ. –

+0

Обновление: я нашел в подпрограмме Fortran, его можно было объявить как характер регулируемой длины, например: CHARACTER (*), намерение (inout) :: A. Это сделает эту схему более мощной, чем я думал. –

+0

10 раз 5 = 50, так почему ХАРАКТЕР * 10, а не ХАРАКТЕР * 50? –

Смежные вопросы