Esme_
Esme_

Reputation: 1520

Solving system of des using method of lines - spatially discretised

I am trying to adapt this example using the method of lines so solve a pde for a system of des. This is not the system I am trying to solve, just an example.

How do I incorporate a second de? I have tried modifying odefunc to be

def odefunc(u,t):
    dudt = np.zeros(X.shape)
    dvdt = np.zeros(X.shape)

    dudt[0] = 0 # constant at boundary condition
    dudt[-1] = 0

    dvdt[0] = 0
    dvdt[-1] = 0


    # for the internal nodes
    for i in range (1, N-1):
        dudt[i] = k* (u[i+1] - 2*u[i] + u[i-1]) / h**2
        dvdt[i] = u[i]
    return [dudt,dvdt]

based on a couple of example solutions of systems of odes I found - but as I already had an array for dudt I suspect this might be my problem. I also don't know what my initial conditions should now look like so they are the correct dimensions etc.

The error I get is The array return by func must be one-dimensional, but got ndim=2. at line sol = odeint(odefunc, init, tspan)

Example with a single pde

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt

plt.interactive(False) 

N = 5 # number of points to discretise
L = 1.0 # length of the rod
X = np.linspace(0,L,N)
h = L/ (N  - 1)

k = 0.02

def odefunc(u,t):
    dudt = np.zeros(X.shape)

    dudt[0] = 0 # constant at boundary condition
    dudt[-1] = 0


    # for the internal nodes
    for i in range (1, N-1):
        dudt[i] = k* (u[i+1] - 2*u[i] + u[i-1]) / h**2
    return dudt

init = 150.0 * np.ones(X.shape) # initial temperature
init[0] = 100.0 # boundary condition
init[-1] = 200.0 # boundary condition

tspan = np.linspace(0.0, 5.0, 100)
sol = odeint(odefunc, init, tspan)

for i in range(0, len(tspan), 5):
    plt.plot(X,sol[i], label = 't={0:1.2f}'.format(tspan[i]))

# legend outside the figure
plt.legend(loc='center left', bbox_to_anchor=(1,0.5))
plt.xlabel('X position')
plt.ylabel('Temperature')

# adjust figure edges so the legend is in the figure
plt.subplots_adjust(top=0.89, right = 0.77)
plt.show()

Upvotes: 1

Views: 447

Answers (1)

Matthew Flamm
Matthew Flamm

Reputation: 620

From the odeint documentation of the ode function defines y to be a vector, but you have it defined as a list of vectors.

Solves the initial value problem for stiff or non-stiff systems of first order odes:

dy/dt = func(y, t, ...) [or func(t, y, ...)]

where y can be a vector.

You can simply use the ravel function to create a vector from a list of vectors. Here is an example from your code:

import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
plt.interactive(False) 
N = 5 # number of points to discretise
L = 1.0 # length of the rod
X = np.linspace(0,L,N)
h = L/ (N  - 1)
k = 0.02
def odefunc2(y,t):
    
    u = y[:N]
    v = y[N:]
    
    dudt = np.zeros_like(u)
    dvdt = np.zeros_like(v)    

    dudt[0] = 0 # constant at boundary condition
    dudt[-1] = 0
    
    dvdt[0] = 0
    dvdt[-1] = 0
    # for the internal nodes
    for i in range (1, N-1):
        dudt[i] = k* (u[i+1] - 2*u[i] + u[i-1]) / h**2
        dvdt[i] = u[i]
    return np.ravel([dudt, dvdt])

initu = 150.0 * np.ones(X.shape) # initial temperature
initu[0] = 100.0 # boundary condition
initu[-1] = 200.0 # boundary condition

initv = np.zeros(X.shape) # initial v

init = np.ravel([initu, initv])

tspan = np.linspace(0.0, 5.0, 100)
sol = odeint(odefunc2, init, tspan)

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2)

for i in range(0, len(tspan)):
    ax1.plot(X, sol[i, :N], label = 't={0:1.2f}'.format(tspan[i]))
    ax2.plot(X, sol[i, N:], label = 't={0:1.2f}'.format(tspan[i]))

plt.show()

Upvotes: 1

Related Questions