在Python中并行求解微分方程

2 投票
3 回答
949 浏览
提问于 2025-04-16 03:35

我正在用 odeint 函数来解决一组普通微分方程。请问,是否可以轻松地将这个问题进行并行处理?如果可以的话,应该怎么做呢?

3 个回答

0

编辑:哇,我刚意识到这个问题已经有超过三年的历史了。我还是决定留下我的回答,希望能帮助到和我有相同困扰的人。抱歉了。

我也遇到过同样的问题。我是这样来实现并行处理的。

首先,你需要用到一个叫 dispy 的工具。在这个工具里,你会找到一些可以帮你实现并行处理的程序。我对 dispy 不是很专业,但我使用起来没有遇到任何问题,也不需要进行复杂的设置。

那么,怎么使用它呢?

  1. 首先运行 python dispynode.py -d。如果你在运行主程序之前不先运行这个脚本,后面的并行任务就不会执行。

  2. 接着运行你的主程序。我在这里贴出我用的那个程序(抱歉有点乱)。你需要修改 sim 这个函数,并根据你想要处理的结果进行相应的调整。不过我希望我的程序能给你提供一些参考。

    import os, sys, inspect
    
    #Add dispy to your path
    cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
    if cmd_folder not in sys.path:
        sys.path.insert(0, cmd_folder)
    
    # use this if you want to include modules from a subforder
    cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],cmd_folder+"/dispy-3.10/")))
    if cmd_subfolder not in sys.path:
        sys.path.insert(0, cmd_subfolder)
    #----------------------------------------#
    #This function contains the differential equation to be simulated.    
    def sim(ic,e,O): #ic=initial conditions; e=Epsiolon; O=Omega 
        from scipy.integrate import ode
        import numpy as np
    
        #Diff Eq.
        def sys(t,x,e,O,z,b,l):
            p = 2.*e*O*np.sin(O*t)*(1-e*np.cos(O*t))/(z+(1-e*np.cos(O*t))**2)
            q = (1+4.*b/l*np.cos(O*t))*(z+(1-e*np.cos(O*t)))/( z+(1-e*np.cos(O*t))**2 )
            dx=np.zeros(2)
            dx[0] = x[1]
            dx[1] = -q*x[0]-p*x[1]
            return dx
        #Simulation.    
        t0=0; tEnd=10000.; dt=0.1
        r = ode(sys).set_integrator('dop853', nsteps=10,max_step=dt) #Definition of the integrator
        Y=[];S=[];T=[]
        # - parameters - # 
        z=0.5; l=1.0; b=0.06;
        # -------------- #
        color=1
        r.set_initial_value(ic, t0).set_f_params(e,O,z,b,l) #Set the parameters, the initial condition and the initial time
        #Loop to integrate.
        while r.successful() and r.t +dt < tEnd:
            r.integrate(r.t+dt)
            Y.append(r.y)
            T.append(r.t)
            if r.y[0]>1.25*ic[0]: #Bound. This is due to my own requirements.
                color=0
                break
            #r.y contains the solutions and r.t contains the time vector.
        return e,O,color #For each pair e,O return e,O and a color (0,1) which correspond to the color of the point in the stability chart (0=unstable) (1=stable)
        # ------------------------------------ #
    
    #MAIN PROGRAM where the parallel magic happens
    import matplotlib.pyplot as plt
    import dispy
    import numpy as np
    F=100 #Total files
    #Range of the values of Epsilon and Omega
    Epsilon = np.linspace(0,1,100)
    Omega_intervals   = np.linspace(0,4,F)
    
    ic=[0.1,0]
    
    cluster = dispy.JobCluster(sim) #This function sets that the cluster (array of processors) will be assigned the job sim.
    jobs = [] #Initialize the array of jobs
    
    for i in range(F-1):
        Data_Array=[]
        jobs = []
        Omega=np.linspace(Omega_intervals[i], Omega_intervals[i+1],10)
        print Omega
        for e in Epsilon:
            for O in Omega:
                job = cluster.submit(ic,e,O) #Send to the cluster a job with the specified parameters
                jobs.append(job) #Join all the jobs specified above
            cluster.wait()
        #Do the jobs
        for job in jobs:
            e,O,color = job()
            Data_Array.append([e,O,color])
    
        #Save the results of the simulation.
        file_name='Data'+str(i)+'.txt'
        f=open(file_name, 'a')
        f.write(str(Data_Array))
        f.close()
    
1

数值积分一个常微分方程(ODE)是一个本质上需要按顺序进行的操作,因为你需要用每一步的结果来计算下一步的结果(当然,如果你是从多个起始点开始积分,那就另当别论了)。所以我想答案是否定的。

2

上面的回答是错的,解决一个常微分方程(ODE)时,通常需要在每次迭代中多次计算函数 f(t,y)=y',比如使用龙格-库塔方法时就需要计算四次。不过我不知道有没有哪个 Python 的库可以做到这一点。

撰写回答