Решение большой системы ODE на Python. Как ускорить и оптимизировать память?

#python #optimization #scipy #generator #odeint

Вопрос:

Я пытаюсь решить большую систему ОД. Мой код работает, но проблема в том, что его запуск занимает слишком много времени. Кроме того, он потребляет много памяти. Итак, не могли бы вы дать рекомендации о том, как ускорить мой код и снизить потребление памяти?

Например, если вы запустите мой conde, используя n=6, код не будет работать (по крайней мере, на моем компьютере 8 ГБ оперативной памяти), потому что для него требуется слишком много памяти.

Кроме того, правильно ли я использую функцию генератора? Спасибо!

 # 1. Libraries
import numba
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import scipy as sci
from numba import jit
from scipy.integrate import odeint
from matplotlib.ticker import MaxNLocator
    
# 2. The model
@numba.jit
def dxidt(xi, t, ao, aj, d, n, m):
    dx = np.zeros(len(xi))
    past_index = np.repeat(np.arange(0, len(xi)), m)
    for i in np.arange(1, len(dx)):
        dx[i] = ao[i-1] * xi[past_index[i-1]] - (d   np.sum(aj[i])) * xi[i]#aj[i-1]
    return(dx)

    
# 3. Parameters
d = 1.
m = np.ones(1, dtype = int) * [2, 4, 8]
n = 5               # Tree levels: Begins at zero!!!!!!!!!!!!!!


s = np.concatenate([np.arange(0., 0.1, 0.001),
                    np.arange(0.1, 1., 0.01),
                    np.arange(1., 10., 0.1),
                    np.arange(10., 100., 1.),
                    np.arange(100., 1010., 10.)])

# 4. Integration conditions
tf = 10#
steps = 100
t = np.linspace(0, tf, steps)

# 5. ODE
## 5.1 ai constant

## 5.2 ai variable
sol2 = []

def ode_generator(d, m, n, s, t):
    for i in np.arange(0, len(m)):
        xi = np.ones(sum(m[i]**np.arange(0, n)))
        xi[1:] = 1.
        aj = np.ones(sum(m[i]**np.arange(0, n 1)) - m[i]**0)
        tau = np.ones(len(aj)) * np.random.uniform(low = 0., high = 1.,
                                                   size = len(aj))
        tau[0:m[i]] = 1. # Coefficients once!!!!!!!!!!!!!!
        print(m[i])
        for j in np.arange(0, len(s)):
            temp = []
            #       temp_test = []
            aj[m[i]:] = (1   s[j] * tau[m[i]:])
            ao = aj[0:sum(m[i]**np.arange(0, n)) - m[i]**0]
            ajt = aj.reshape(int(len(aj)/m[i]), m[i])
            init_cond = xi
            print("m =", m[i], "s =", s[j])
            temp = sci.integrate.odeint(dxidt, init_cond, t, args=(ao, ajt, d, n, m[i]))[-1]
            yield temp



## 6.2. Eq. Abundance vs m vs s (ai variable)
eqsol2 = []
for sol in ode_generator(d, m, n, s, t):
    eqsol2.append(sol)

 

Комментарии:

1. Не могли бы вы подробнее объяснить свою проблему? Похоже , для n=6 этого у вас будет около 300 000 уравнений? odeint это экономит 300 000 переменных за несколько сотен временных шагов, так что, возможно, это экономит около 30e6 значений двойной точности, а может быть, и больше. Это примерно 0,3 ГБ. Вы добавляете результаты в большой список eqsol2 . Было бы лучше сохранить результаты в двоичных файлах. pickle Например, поиск файлов.

2. Привет. Вы довольно хорошо описали проблему. Да, для n=6 существует около 300 тысяч ОДУ, так что это потребляет много памяти. Я использую генераторы, поскольку я предполагаю, что они избегают хранения временных данных (не уверен, я в этом не разбираюсь), сокращая потребление памяти, но я не уверен, хорошо ли я их кодирую. Я проверю библиотеку Пикля. Спасибо!