Эффективный способ хранения и загрузки параметров в итеративно вызываемой функции - PullRequest
0 голосов
/ 17 июня 2020

Я работал над проблемой, когда мне нужно смоделировать систему. Я вырезал соответствующий код, который написал только для тех частей, которые важны для этого вопроса. реализует параметры. Я бы предпочел хранить параметры где-нибудь, чтобы сделать их легко редактируемыми, поскольку я, вероятно, буду использовать эти функции в нескольких других файлах, но я предполагаю, что эта функция будет продолжать выделять параметры при каждом вызове ode_3DOF_oscillator (state, t, u). Есть ли лучший способ go об этом?

1 Ответ

1 голос
/ 18 июня 2020

просто для объяснения вашего существующего кода каждая итерация решателя ODE Python должна:

  1. вызывать ode_3DOF_oscillator, который немедленно вызывает oscillatorParams
  2. локальные переменные получают установить в свой параметр переменные
  3. локальные переменные превращаются в кортеж, а функция возвращает
  4. возвращаемый кортеж распаковывается в набор локальных переменных для использования позже
  5. остальная часть ваш код работает до тех пор, пока он не вернет результат

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

def make_3DOF_oscillator():
    K1,K2,K3 = 1e5,1e6,1e2
    B1,B2,B3 = 100,100,100
    a1,a2,a3 = 1,1,1
    b1,b2,b3 = 1,1,1
    I1,I2,I3 = 1000,10000,20000

    def fn(state, t, u):
        # ..equations for the odesolver..
        return [omega[0],omega[1],omega[2],dw1dt,dw2dt,dw3dt]

    return fn

def runSim(u,dt,T):
    myfn = make_3DOF_oscillator()
    t=np.arange(0,T,dt) ; N=len(t)
    for i in range(0, N ):
        if i==N-1 or i==N:
            tt = [t[i], t[i]]  # [t1 t2]
        else:
            tt = [t[i], t[i+1]]  # [t1 t2]
        x=odeint(myfn, x0,tt,args=(M[i,:],))
    return t,y1,y2,y3

это приводит к хорошая производительность, поскольку параметры напрямую доступны в функции fn как локальные переменные (в отличие от глобальных, которые работают немного медленнее). кроме того, параметры устанавливаются только один раз, а не на каждом шаге.

в противном случае, если производительность не является проблемой и вы не возражаете, если набираете немного больше, вы можете использовать классы:

class Oscillator3DOF:
    def __init__(self):
        self.K1, self.K2, self.K3 = 1e5,1e6,1e2
        self.B1, self.B2, self.B3 = 100,100,100
        self.a1, self.a2, self.a3 = 1,1,1
        self.b1, self.b2, self.b3 = 1,1,1
        self.I1, self.I2, self.I3 = 1000,10000,20000

    def deriv(self, y, t, u):
        # ..equations for the odesolver..
        return [omega[0],omega[1],omega[2],dw1dt,dw2dt,dw3dt]

def runSim(u,dt,T):
    system = Oscillator3DOF()
    t=np.arange(0,T,dt) ; N=len(t)
    for i in range(0, N ):
        if i==N-1 or i==N:
            tt = [t[i], t[i]]  # [t1 t2]
        else:
            tt = [t[i], t[i+1]]  # [t1 t2]
        x=odeint(system.deriv, x0,tt,args=(M[i,:],))
    return t,y1,y2,y3

обратите внимание, что deriv будет обращаться к параметрам как self.K1 et c.

другой вариант - использовать что-то вроде namedtuple s для однократного сохранения ваших параметров. это упростило бы сохранение значений параметров вне исходного кода, что может быть желательным свойством

не совсем уверен, для чего нужны ваши параметры M и u, но я бы хотел настроить их таким же образом. например, передать их в make_3DOF_oscillator(M[i,:]), что делает его доступным в fn, или сохранить как переменную-член в конструкторе Oscillator3DOF. в этих случаях вам нужно создать объекты в пределах for i l oop, чтобы он получил доступ к нужному

...