简体   繁体   English

使用 numpy.piecewise 的问题

[英]Problems using numpy.piecewise

1. The core problem and question一、核心问题和疑问

I will provide an executable example below, but let me first walk you through the problem first.我将在下面提供一个可执行示例,但首先让我先引导您解决问题。

I am using solve_ivp from scipy.integrate to solve an initial value problem ( see documentation ).我正在使用solve_ivp中的scipy.integrate来解决初始值问题( 请参阅文档)。 In fact I have to call the solver twice, to once integrate forward and once backward in time.事实上,我必须调用求解器两次,一次向前积分,一次向后积分。 (I would have to go unnecessarily deep into my concrete problem to explain why this is necessary, but please trust me here--it is!) (我将不得不对 go 不必要地深入我的具体问题来解释为什么这是必要的,但请相信我——它是!)

sol0 = solve_ivp(rhs,[0,-1e8],y0,rtol=10e-12,atol=10e-12,dense_output=True)
sol1 = solve_ivp(rhs,[0, 1e8],y0,rtol=10e-12,atol=10e-12,dense_output=True)

Here rhs is the right hand side function of the initial value problem y(t) = rhs(t,y) .这里rhs是初始值问题y(t) = rhs(t,y)的右手边 function 。 In my case, y has six components y[0] to y[5] .在我的例子中, y有六个分量y[0]y[5] y0=y(0) is the initial condition. y0=y(0)是初始条件。 [0,±1e8] are the respective integration ranges, one forward and the other backward in time. [0,±1e8]是各自的积分范围,一个在时间上向前,另一个在时间上向后。 rtol and atol are tolerances. rtolatol是公差。

Importantly, you see that I flagged dense_output=True , which means that the solver does not only return the solutions on the numerical grids, but also as interpolation functions sol0.sol(t) and sol1.sol(t) .重要的是,您看到我标记dense_output=True ,这意味着求解器不仅返回数值网格上的解,还返回插值函数sol0.sol(t)sol1.sol(t)

My main goal now is to define a piecewise function, say sol(t) which takes the value sol0.sol(t) for t<0 and the value sol1.sol(t) for t>=0 .我现在的主要目标是定义一个分段的 function,比如sol(t) ,它的t<0值为sol0.sol(t) sol1.sol(t)t>=0的值为 sol1.sol(t)。 So the main question is: How do I do that?所以主要问题是:我该怎么做?

I thought that numpy.piecewise should be tool of choice to do this for me.我认为numpy.piecewise应该是为我执行此操作的首选工具。 But I am having trouble using it, as you will see below, where I show you what I tried so far.但是我在使用它时遇到了麻烦,正如您将在下面看到的那样,我向您展示了到目前为止我尝试过的内容。


2. Example code 2.示例代码

The code in the box below solves the initial value problem of my example.下面方框中的代码解决了我的例子的初值问题。 Most of the code is the definition of the rhs function, the details of which are not important to the question.大部分代码是rhs function 的定义,其中的细节对问题并不重要。

import numpy as np
from scipy.integrate import solve_ivp

# aux definitions and constants
sin=np.sin; cos=np.cos; tan=np.tan; sqrt=np.sqrt; pi=np.pi;  
c  = 299792458
Gm = 5.655090674872875e26    

# define right hand side function of initial value problem, y'(t) = rhs(t,y)
def rhs(t,y):
    p,e,i,Om,om,f = y
    sinf=np.sin(f); cosf=np.cos(f); Q=sqrt(p/Gm); opecf=1+e*cosf;        

    R = Gm**2/(c**2*p**3)*opecf**2*(3*(e**2 + 1) + 2*e*cosf - 4*e**2*cosf**2)
    S = Gm**2/(c**2*p**3)*4*opecf**3*e*sinf         

    rhs    = np.zeros(6)
    rhs[0] = 2*sqrt(p**3/Gm)/opecf*S
    rhs[1] = Q*(sinf*R + (2*cosf + e*(1 + cosf**2))/opecf*S)
    rhs[2] = 0
    rhs[3] = 0
    rhs[4] = Q/e*(-cosf*R + (2 + e*cosf)/opecf*sinf*S)
    rhs[5] = sqrt(Gm/p**3)*opecf**2 + Q/e*(cosf*R - (2 + e*cosf)/opecf*sinf*S)

    return rhs

# define initial values, y0
y0=[3.3578528933149297e13,0.8846,2.34921,3.98284,1.15715,0]

# integrate twice from t = 0, once backward in time (sol0) and once forward in time (sol1)
sol0 = solve_ivp(rhs,[0,-1e8],y0,rtol=10e-12,atol=10e-12,dense_output=True)
sol1 = solve_ivp(rhs,[0, 1e8],y0,rtol=10e-12,atol=10e-12,dense_output=True)

The solution functions can be addressed from here by sol0.sol and sol1.sol respectively. sol0.solsol1.sol可以分别从这里解决解函数。 As an example, let's plot the 4th component:例如,让我们 plot 第 4 个组件:

from matplotlib import pyplot as plt

t0 = np.linspace(-1,0,500)*1e8
t1 = np.linspace( 0,1,500)*1e8
plt.plot(t0,sol0.sol(t0)[4])
plt.plot(t1,sol1.sol(t1)[4])
plt.title('plot 1')
plt.show()

在此处输入图像描述


3. Failing attempts to build piecewise function 3. 未能尝试构建分段 function

3.1 Build vector valued piecewise function directly out of sol0.sol and sol1.sol 3.1 直接从sol0.solsol1.sol

def sol(t): return np.piecewise(t,[t<0,t>=0],[sol0.sol,sol1.sol])
t = np.linspace(-1,1,1000)*1e8
print(sol(t))

This leads to the following error in piecewise in line 628 of.../numpy/lib/function_base.py:这导致.../numpy/lib/function_base.py的第628行分段出现以下错误:

TypeError: NumPy boolean array indexing assignment requires a 0 or 1-dimensional input, input has 2 dimensions

I am not sure, but I do think this is because of the following: In the documentation of piecewise it says about the third argument:我不确定,但我确实认为这是因为以下原因:在分段的文档中,它谈到了第三个参数:

funclistlist of callables, f(x,*args,**kw), or scalars可调用对象、f(x,*args,**kw) 或标量的 funclistlist

[...]. [...]。 It should take a 1d array as input and give an 1d array or a scalar value as output.它应该将一维数组作为输入,并给出一维数组标量值output。 [...]. [...]。

I suppose the problem is, that the solution in my case has six components.我想问题是,我的解决方案有六个组成部分。 Hence, evaluated on a time grid the output would be a 2d array.因此,在时间网格上评估 output 将是一个二维数组。 Can someone confirm, that this is indeed the problem?有人可以确认,这确实是问题吗? Since I think this really limits the usefulness of piecewise by a lot.因为我认为这确实大大限制了piecewise的有用性。

3.2 Try the same, but just for one component (eg for the 4th) 3.2 尝试相同,但只针对一个组件(例如第四个)

def sol4(t): return np.piecewise(t,[t<0,t>=0],[sol0.sol(t)[4],sol1.sol(t)[4]])
t = np.linspace(-1,1,1000)*1e8
print(sol4(t))

This results in this error in line 624 of the same file as above:这会导致与上述相同文件的第 624 行出现此错误:

ValueError: NumPy boolean array indexing assignment cannot assign 1000 input values to the 500 output values where the mask is true

Contrary to the previous error, unfortunately here I have so far no idea why it is not working.与之前的错误相反,不幸的是,到目前为止我还不知道它为什么不起作用。

3.3 Similar attempt, however first defining functions for the 4th components 3.3 类似的尝试,但首先为第 4 个组件定义功能

def sol40(t): return sol0.sol(t)[4]
def sol41(t): return sol1.sol(t)[4]
def sol4(t): return np.piecewise(t,[t<0,t>=0],[sol40,sol41])
t = np.linspace(-1,1,1000)
plt.plot(t,sol4(t))
plt.title('plot 2')
plt.show()

在此处输入图像描述

Now this does not result in an error, and I can produce a plot, however this plot doesn't look like it should.现在这不会导致错误,我可以生成 plot,但是这个 plot 看起来不应该。 It should look like plot 1 above.它应该看起来像上面的 plot 1 。 Also here, I so far have no clue what is going on.同样在这里,到目前为止,我不知道发生了什么。

Am thankful for help!感谢您的帮助!

You can take a look to numpy.piecewise source code.您可以查看numpy.piecewise源代码。 There is nothing special in this function so I suggest to do everything manually.这个 function 没有什么特别之处,所以我建议手动完成所有操作。

def sol(t):
    ans = np.empty((6, len(t)))
    ans[:, t<0] = sol0.sol(t[t<0])
    ans[:, t>=0] = sol1.sol(t[t>=0])
    return ans

Regarding your failed attempts.关于你失败的尝试。 Yes, piecewise excpect functions return 1d array.是的, piecewise excpect 函数返回一维数组。 Your second attempt failed because documentation says that funclist argument should be list of functions or scalars but you send the list of arrays.您的第二次尝试失败了,因为文档说funclist参数应该是函数列表或标量列表,但您发送了 arrays 列表。 Contrary to the documentation it works even with arrays, you just should use the arrays of the same size as t < 0 and t >= 0 like:与文档相反,即使使用 arrays,您也应该使用与t < 0t >= 0大小相同的 arrays,例如:

def sol4(t): return np.piecewise(t,[t<0,t>=0],[sol0.sol(t[t<0])[4],sol1.sol(t[t>=0])[4]])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM