Estoy tratando de usar un modelo numérico Fortran90 con Python 3.5 usando f2py.

f2py -c module.f90 -m mod --fcompiler=gfortran

El modelo es un módulo Fortran que contiene variables, funciones y subrutinas. Estoy publicando aquí un ejemplo de código que tiene todas las características del modelo numérico.

module modul

implicit none
integer :: inte
real :: re
integer, dimension(3) :: array
CHARACTER(*), PARAMETER :: chara = "helloWorld"

contains
    integer function fun()
        fun = array(1) + array(2) + array(3)
    end function

    subroutine subrout(a,b)
        real, intent(out) :: b
        integer, intent(out) :: a
        a = inte + fun()
        b = re
        write(*,*) chara
    end subroutine subrout

end module modul

La conversión del código con f2py funciona correctamente, pero cuando importo el módulo en Python, recibo un error de segmentación

>>> import mod
Segmentation fault (core dumped)

Me di cuenta de que el problema depende de la dimensión no especificada de la matriz de caracteres

CHARACTER(*), PARAMETER :: chara = "helloWorld"

Como, si elimino esa línea de código o asigno una dimensión fija a la matriz (como CHARACTER (20)), el módulo funciona correctamente en Python.

1. ¿Hay alguna manera de hacerlo funcionar sin modificar el código Fortran? (el modelo es largo y complejo y, si es posible, no quiero trabajar en ello)?

Las matrices de caracteres se utilizan para definir cadenas en el código (como mensajes de error) y para manejar la entrada / salida de los archivos. Una forma de resolver el problema (si no hay respuesta a la pregunta 1) podría ser definir una dimensión máxima fija para todas las cadenas de caracteres (es decir, INTEGER, PARAMETER :: lenChar = 100) y luego usar

CHARACTER(lenChar), PARAMETER :: chara

En lugar de la declaración anterior. En este caso, el módulo se importa con éxito en Python, pero cuando intento modificar el contenido de la matriz requiere una entrada lenChar long (el mismo problema aparece con los otros tipos de matriz como INTEGER o REAL y no depende del atributo PARAMETER)

mod.modul.chara = "hello"
0-th dimension must be fixed to 100 but got 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SystemError: error return without exception set

Esta es una operación que el modelo debe manejar, ya que la "chara" podría ser la ruta de los datos y debe inicializarse en tiempo de ejecución.

2. Si no hay respuesta a la pregunta (1) y necesito proceder de esta manera, ¿cómo puedo asignar a la matriz una entrada más corta que la longitud de la matriz?

System information:
OS: Ubuntu 16.04
Python 3.5.2
f2py Version:     2
numpy Version: 1.12.1
GNU Fortran (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
1
Dalmo1991 6 abr. 2017 a las 11:40

2 respuestas

La mejor respuesta

Respondiendo la pregunta 2:

Las cadenas en fortran se tratan como una matriz de caracteres en f2py. Entonces, en su caso, mod.modul.chara es una matriz de 100 caracteres (dependiendo de la longitud especificada en fortran). Para alimentar algo como 'hello' en el controlador, puede hacer lo siguiente:

for i,j in enumerate('hello'):
    mod.modul.chara[i]=j

Esto debería permitirle pasar la cadena.

1
Ash Sharma 6 abr. 2017 a las 11:17

Parece confundir cadenas de longitud variable (sea lo que sea, algo así en Fortran 2003), constantes de cadena y argumentos ficticios que toman la longitud de lo que pasa. Probablemente quieras:

subroutine sub(ch)
  character(*), intent(in) :: ch

  print *, ch
end

Esto es algo completamente diferente de su ejemplo. Aquí el argumento ch aceptará cualquier longitud de cadena que pase allí.


El problema está en la constante de caracteres de longitud supuesta. Esto es suficiente para provocar el error.

module m
  CHARACTER(*), PARAMETER :: chara = "helloWorld"
end module m

Esta NO es una matriz de caracteres, es una cadena de caracteres escalar de longitud supuesta.

Es exactamente equivalente a

module m
  CHARACTER(10), PARAMETER :: chara = "helloWorld"
end module m

La única diferencia es que el compilador obtiene la longitud automáticamente en el primer caso si usted es perezoso para contar la longitud manualmente (o si la cambia de vez en cuando).

La última versión funciona correctamente en f2py:

f2py -c -m f2pychar f2pychar.f90 

ipython

In [1]: import f2pychar 

In [2]: print f2pychar.modul.chara
['h' 'e' 'l' 'l' 'o' 'W' 'o' 'r' 'l' 'd']

F2py debería entenderlo, pero parece que no. Es un error grave en f2py. Simplemente ingrese la longitud manualmente como en el último ejemplo anterior. No hay diferencia, el código es euivalente.


A tu número (2). NO es una matriz (en Fortran). Las reglas para las matrices no se aplican aquí. Pero lo más importante, es una constante, no se le puede asignar nada, por lo que realmente no entiendo lo que quieres decir. Si tiene una variable de caracteres, puede asignar una cadena más corta sin problema:

character(10) :: ch = "abcd"
1
Vladimir F 6 abr. 2017 a las 12:24