从 JiTCDDE 实例获取派生值

Getting derivative value from JiTCDDE instance

我正在使用 JiTCDDE 模块求解延迟微分方程。我的工作要求我让模型演化一段时间,然后再扰乱它。为此,我尝试使用 jitcdd.purge_past(),然后使用 jitcdde.add_past_points()。问题是,后者不仅要求我提供输入时的值,还要提供导数的值。

有没有办法从 jitcdde 实例本身获取它们,还是我需要手动笨拙地计算它们?

编辑:更多信息

我的系统由两个耦合在一起的非线性振荡器组成(它们不是相位振荡器)。我让系统演化一段时间,直到它达到稳定状态,然后通过稍微及时移动两个振荡器之一来扰动它。我将其移动的量计算为振荡周期的百分比,相当于有效相移。

我的系统是 12 维的,我正在努力minimal working example,所以这里是一个无法正常工作的代码模型:

f = [...]
DDE = jitcdde(f)
DDE.constant_past([1]*len(f))
DDE.step_on_discontinuities()

initial_integration_time = 30
DDE.integrate(initial_integration_time)

完成此操作后,我想执行应该的扰动,比如说 10% 的周期,假设我知道静止周期长度为 T。我正在尝试做的是使用 get_state 来获取系统和导数的当前状态,以及 perturbation 时间单位之前的状态和导数。然后,我可以构建一组新的 anchor,我可以将其传递给 DDE.add_past_points 以从那里开始整合。

T = ...
perturbation = 0.1*T #in units of time

state = DDE.get_state()
# get position and derivative of first oscilator
# since the system is 12-D, the first six correspond to osc1
osc1_x = [state[1][6:] for s in state]
osc1_dx = [state[2][6:] for s in state]

# here, do the same for osc2 at DDE.t - perturbation

问题

要回答所发布的问题,要从 jitcdde 实例中获取导数,您需要做的就是调用 get_state 方法。假设 DDE 是您已经集成的 jitcdde 实例:

state = DDE.get_state()
derivatives = [s[2] for s in state]

这是有效的,因为 get_state 将 return Cubic Hermite Spline instance that behaves basically like a list of tuples (plus some cool methods) where each tuple contains a time, the state of the system at that time and the derivatives of the system at that time, see this entry in the docs 以获取更多信息。


我的问题

为了具体解决我的问题,如果有路人关心,我做了以下操作(代码与问题的模型样式相同):

# define and initialize system
f = [...]
DDE = jitcdde(f)
DDE.constant_past([1]*len(f))
DDE.step_on_discontinuities()

initial_integration_time = 30
T = ... # period length
perturbation = 0.1*T # 10% of period, in units of time

# get state of system at perturbation time units before the 
# end of the initial integration
DDE.integrate(initial_integration_time-perturbation)
state1 = DDE.get_state.copy()

# get state after initial integration is done
DDE.integrate(initial_integration_time)
state2 = DDE.get_state()

# generate new anchors from these set of states
eps = 1e-6
anchors = []
for i, s in enumerate(state2[::-1]): #iterate in reverse
    # stop if I reached the end, there's no telling 
    # which states is gonna be longer
    if i >= len(state1):
        break
    
    # calculate new anchor at the time of the anchor I'm looking at
    # shifted by the perturbation length
    tt = s[0] - perturbation_duration
    state1.interpolate_anchor(tt)
    _, x1, dx1 = state1[state1.last_index_before(tt+eps)]
    
    x_new = np.hstack( (x1[:6], s[1][6:]) )
    dx_new = np.hstack( (dx1[:6], s[2][6:]) )
    anchors.append( (tt, x_new, dx_new) )

# add this new past to the integrator and evolve the system
DDE.purge_past()
DDE.add_past_points(anchors)
DDE.step_on_discontinuities()

# now I can evolve the system as I please

此代码有一些注意事项,例如确保扰动不会太大以及状态足够长,但这是我的解决方案背后的基本思想。我不会详细解释它的作用,因为我认为它不会对任何人有指导意义。