Pasando matrices de formato de cadena numpy a fortran usando f2py

Mi objective es imprimir la segunda cadena desde una matriz de python numpy en fortran, pero solo imprimo el primer carácter, y tampoco es necesariamente la cadena correcta.

¿Alguien puede decirme cuál es la forma correcta de pasar matrices de cadenas completas a Fortran?

El código es el siguiente:

testpy.py

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

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 

Comstackdo con

 f2py -c -m testa4 testa4.f90 

Salida del código anterior

 c 

Salida deseada

 bb 

No sé cómo hacerlo usando f2py . Pero se puede hacer con ctypes . Obtiene una matriz de caracteres, pero puede convertirla en una cadena muy fácilmente.

 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 

comstackr: 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) 

correr:

 > python testpy.f90 bb 

Según la documentación , a f2py le gusta que se pasen matrices de cadenas con dtype = ‘c’ (es decir, ‘| S1’). Esto te lleva a una parte del camino allí, aunque hay algunas rarezas con la forma de la matriz detrás de la escena (por ejemplo, en muchas de mis pruebas descubrí que fortran mantendría la longitud de 2 caracteres, pero interpretaría los 6 caracteres como indicativos de una matriz de 2×6, así que obtendría memoria aleatoria de nuevo en la salida). Esto (por lo que pude ver), requiere que usted trate la matriz de Fortran como una matriz de caracteres 2D (a diferencia de una matriz de “cadena” 1D). Desafortunadamente, no pude que tomara una forma asumida y terminé pasando el número de cadenas como un argumento.

Estoy bastante seguro de que me estoy perdiendo algo bastante obvio, pero esto debería funcionar por el momento. En cuanto a por qué CHARACTER * 2 no funciona … Sinceramente, no tengo idea.

 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 

No es realmente una respuesta, pero es demasiado largo para comentar: tal vez esto ayude …

en su primer caso, lo que se pasa a fortran es, por alguna razón, el primer carácter de cada cadena:

 'abc' 

que en Fortran termina en la longitud de 2 matrices como ‘ab’, ‘c’. Si trabajas estrictamente con la longitud de una cadena, todo está bien, supongo. Desafortunadamente, no puede falsificar el sistema y dividirlo en una matriz de un solo carácter en python ['a','a','b','b'.. – arroja un error si las longitudes de la matriz no coinciden.

En su segunda pregunta, si declara con la

  character*2 

notación, en realidad funciona simplemente para pasar una lista de cadenas de python regular:

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

(y ahora arroja un error si intenta la matriz de cadenas numpy). Las cadenas deben tener la longitud correcta exacta o también produce un error aquí.