python memory-management fortran out-of-memory f2py

python - ¿Por qué mi código Fortran está envuelto con f2py usando tanta memoria?



memory-management out-of-memory (1)

Estoy tratando de calcular todas las distancias entre aproximadamente cien mil puntos. Tengo el siguiente código escrito en Fortran y compilado usando f2py :

C 1 2 3 4 5 6 7 C123456789012345678901234567890123456789012345678901234567890123456789012 subroutine distances(coor,dist,n) double precision coor(n,3),dist(n,n) integer n double precision x1,y1,z1,x2,y2,z2,diff2 cf2py intent(in) :: coor,dist cf2py intent(in,out):: dist cf2py intent(hide)::n cf2py intent(hide)::x1,y1,z1,x2,y2,z2,diff2 do 200,i=1,n-1 x1=coor(i,1) y1=coor(i,2) z1=coor(i,3) do 100,j=i+1,n x2=coor(j,1) y2=coor(j,2) z2=coor(j,3) diff2=(x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2) dist(i,j)=sqrt(diff2) 100 continue 200 continue end

Estoy compilando el código setup_collision.py usando el siguiente código python setup_collision.py :

# System imports from distutils.core import * from distutils import sysconfig # Third-party modules import numpy from numpy.distutils.core import Extension, setup # Obtain the numpy include directory. This logic works across numpy versions. try: numpy_include = numpy.get_include() except AttributeError: numpy_include = numpy.get_numpy_include() # simple extension module collision = Extension(name="collision",sources=[''./collision.f''], include_dirs = [numpy_include], ) # NumyTypemapTests setup setup( name = "COLLISION", description = "Module calculates collision energies", author = "Stvn66", version = "0.1", ext_modules = [collision] )

Luego ejecutarlo de la siguiente manera:

import numpy as np import collision coor = np.loadtxt(''coordinates.txt'') n_atoms = len(coor) dist = np.zeros((n_atoms, n_atoms), dtype=np.float16) # float16 reduces memory n_dist = n_atoms*(n_atoms-1)/2 n_GB = n_dist * 2 / float(2**30) # 1 kB = 1024 B n_Gb = n_dist * 2 / 1E9 # 1 kB = 1000 B print ''calculating %d distances between %d atoms'' % (n_dist, n_atoms) print ''should use between %f and %f GB of memory'' % (n_GB, n_Gb) dist = collision.distances(coor, dist)

Usando este código con 30,000 átomos, lo que debería usar alrededor de 1 GB de memoria para almacenar las distancias, en su lugar usa 10 GB. Con esta diferencia, realizar este cálculo con 100.000 átomos requerirá 100 GB en lugar de 10 GB. Solo tengo 20 GB en mi computadora.

¿Me estoy perdiendo algo relacionado con pasar los datos entre Python y Fortran? La gran diferencia indica un defecto importante en la implementación.


Está alimentando matrices de doble precisión a la subrutina Fortran. Cada elemento con doble precisión requiere 8 bytes de memoria. Para N=30,000 eso hace

coor(n,3) => 30,000*3*8 ~ 0.7 MB dist(n,n) => 30,000^2*8 ~ 6.7 GB

Dado que los flotantes de media precisión son necesarios para Python, eso representa otro 1-2GB. Entonces el requisito general es 9-10GB.

Lo mismo es válido para N=100,000 , que requerirá ~ 75GB para la parte de Fortran solo.

En lugar de flotadores de double precision , debe usar valores real precisión simple, si eso es suficiente para sus cálculos. Esto llevará a la mitad de los requisitos de memoria. [No tengo experiencia con eso, pero supongo que si ambas partes usan la misma precisión, Python puede operar los datos directamente ...]

Como @VladimirF señaló en su comentario, "los compiladores habituales no admiten reales de 2 bytes" . Comprobé con gfortran e ifort , y los dos no. Entonces necesitas usar al menos una sola precisión.