跳转至

code

mcm2023.py

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.integrate import odeint
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 获取某种生物的内禀增长率b,参数为温度(℃),降水量(mm)
def getb(x,y,mu1,mu2,sigma1,sigma2):
    arr=[]
    for index in range(x.size):
        arr.append(3*np.e**(-2*np.log(3)*(
            ((x[index]-mu1)**2/(1*sigma1**2)) + ((y[index]-mu2)**2/(1*sigma2**2))
        )))
    return 10*np.array(arr)

# 生成随机温度、降水量序列
def genRandomWeather(num_of_slices):
    weather = np.array([np.random.randint(20, 35, num_of_slices),np.random.randint(200/12, 1200/12, num_of_slices)])
    return weather

# 生成随机一年内温带大陆气候
def genRandomContinentalWeather(num_of_slices):
    temp=np.array([-13.0,-10.0,-2,7,15,21,27,20,14,6,-3,-10])
    pre=np.array([10.0,11,10,30,40,50,110,120,60,50,23,10])
    for index in range(2):
        temp=np.append(temp,temp)
        pre=np.append(pre,pre)
    temp+=np.random.randint(-3,3,size=num_of_slices)
    pre+=np.random.randint(-8,8,size=num_of_slices)
    # temp[24:36]=25
    pre[24:36]/=10
    return np.array([temp,pre])

def genDroughtWeatherMoreFrequent(num_of_slices):
    temp=np.array([13.0,10.0,12,17,15,21,22,20,14,16,13,10])+10
    pre=np.array([40.0,60,60,67,70,77,110,120,81,66,73,80])
    for index in range(2):
        temp=np.append(temp,temp)
        pre=np.append(pre,pre)
    temp+=np.random.randint(-2,2,size=num_of_slices)
    pre+=np.random.randint(-8,8,size=num_of_slices)
    pre[14:42]/=200
    temp[14:18]+=10
    temp[14:20]+=8
    temp[20:27]+=10
    temp[27:29]+=10
    temp[29:38]+=10
    # temp[14:42]+=np.random.randint(-4,4,size=28)
    # pre[18:20]/=20
    # pre[23:28]/=20
    # pre[15:18]/=20
    return np.array([temp,pre])

# 生成指定长度,固定温度的序列,参数为指定温度、降水量,长度
def genWeather(temperature,precipitation,num_of_slices):
    weather=np.array([np.full(num_of_slices,temperature),np.full(num_of_slices,precipitation)])
    return weather

# 计算其最适宜温度与最适宜年降水量
def calcBestTP(tmin,tmax,pmin,pmax):
    return np.array([(tmin+tmax)/2,(pmin+pmax)/2])

# 获取特定物种适宜温度与降水量
def getCSV(id):
    df=pd.read_csv('species.csv')
    df.values[id][3]/=12
    df.values[id][4]/=12
    return df.values[id]

def getWeatherCSV(filename):
    return pd.read_csv(filename)

def simDroughtWeather(num_of_slices):
    weather = np.array([np.random.randint(34, 36, num_of_slices),np.random.randint(400/12, 600/12, num_of_slices)])
    weather[1][int(num_of_slices/2):]-=33
    # weather[0][int(num_of_slices/2):]+=np.random.randint(0,10)
    return weather

# 计算抗干旱能力
def calcEta(arr :list):
    # arr.T[0].size
    eta=0
    div=arr[0].size
    for index in range(arr[0].size):
        if (arr.T[index][int(arr.T[0].size/2)+1:int(arr.T[0].size/2)+4]<1e-5).any():
            # div-=1
            print("!")
        else:
            eta+=np.sum(arr.T[index][int(arr.T[0].size/2)+1:int(arr.T[0].size/2)+4])/np.sum(arr.T[index][int(arr.T[0].size/2)-4:int(arr.T[0].size/2)-1])
    return eta/div

def drawWeather(t:list,weather:list):
    fig, ax1 = plt.subplots()
    ax1.bar(t,weather[1])
    ax1.set_ylabel("avg precipitation(mm)")
    ax1.tick_params('y')
    ax2 = ax1.twinx()
    ax2.plot(t,weather[0],color="red")
    ax2.scatter(t, weather[0], marker='o',color="r")
    ax2.set_ylabel("avg temperature(℃)")
    ax2.tick_params('y')
    ax2.set_ylim(0, 40)
    ax1.set_xlabel("month")
    plt.show()

if __name__=="__main__":
    a=np.array([33,22,11,23,32,21])
    c=np.array([444,333,222,112,1433,1222])
    print(getb(a,c,10,800,10,900))

Q1.py

from mcm2023 import *
from Q1_SimWeather import *
# 物种数量
N=3
# 切片数
num_of_slices=48

def func(x: list, t, b: list, a: list):
    dx0dt = x[0] * (b[0][int(t)] - a[0][0] * x[0] - a[0][1] * x[1] + a[0][2] * x[2])
    dx1dt = x[1] * (b[1][int(t)] - a[1][0] * x[0] - a[1][1] * x[1] + a[1][2] * x[2])
    dx2dt = x[2] * (b[2][int(t)] + a[2][0] * x[0] + a[2][1] * x[1] - a[2][2] * x[2])
    return [dx0dt, dx1dt, dx2dt]

t = np.linspace(0, num_of_slices-1, num_of_slices)
t = [int(x) for x in t]
x0 = [20, 20, 20]

a=np.full((N,N),0.3)
for index in range(a[0].size):
    a[index][index]=0.5
a*=1.4
b=np.zeros((N,num_of_slices))

# weather=
weather=np.array([[24 ,33, 28 ,24 ,22 ,21, 24 ,26 ,21 ,25 ,28, 30 ,30, 20, 34, 33, 27, 28, 28, 26, 32, 28, 29, 26,
  24 ,34, 32, 23, 24, 27, 29, 33, 20, 32, 31, 29, 28, 30, 34, 20, 32, 25, 23, 27, 27, 25, 28, 27,],
 [69 ,40, 96, 17, 20, 80, 88, 80, 16, 80, 73, 86, 64, 37, 96, 76, 59, 47, 46, 52, 76, 32, 98, 78,
  29 ,29, 33, 28, 68, 89, 21, 95, 96, 65, 21, 33, 24, 76, 26, 20, 99, 24, 19, 64, 48, 92, 20, 73]])
# print(weather)
# weather=genRandomContinentalWeather(num_of_slices)
# weather=genDroughtWeatherMoreFrequent(num_of_slices)
# weather=getColoradoWeather()
# weather=genWeather(24,1000,num_of_slices)
# drawWeather(t,weather)
for index in range(N):
    df=getCSV(index)
    b[index]=getb(weather[0],weather[1],
        (df[1]+df[2])/2,
        (df[3]+df[4])/2,
        (df[2]-df[1]),
        (df[4]-df[3])
    )

sol = odeint(func, x0, t, args=(b, a))
print(sol)
plt.plot(t, sol.T[0], label="species 1",color="lightsalmon")
plt.plot(t, sol.T[1], label="species 2",color="lawngreen")
plt.plot(t, sol.T[2], label="species 3",color="lightskyblue")
plt.fill_between(t, sol.T[0], color='lightsalmon', alpha=0.1)
plt.fill_between(t, sol.T[1], color='lawngreen', alpha=0.1)
plt.fill_between(t, sol.T[2], color='blue', alpha=0.1)
# plt.plot(weather[2], sol.T[0], label="species 1")
# plt.plot(weather[2], sol.T[1], label="species 2")
# plt.plot(weather[2], sol.T[2], label="species 3")

plt.xlabel("month")
plt.ylabel("num")
plt.grid()
plt.legend()
plt.show()

Q1_SimWeather.py

from mcm2023 import *
def getColoradoWeather():
    data=getWeatherCSV("Colorado.csv")
    data['TIMESTAMP'] = pd.to_datetime(data['TIMESTAMP'])
    data=data[((data['TIMESTAMP'].dt.day == 1) | (data['TIMESTAMP'].dt.day == 15))& (data['TIMESTAMP'].dt.hour == 12)]
    data=data.values.T
    rain_permonth=np.array([])
    temp=25.4*np.array([1.34,1.85,1.1,0.71,0.79,0.59,0.39,0.39,0.75,1.26,1.42,2.36])
    for index in range(8):
        rain_permonth=np.append(rain_permonth,temp)
    return np.array([5+data[17][:96],rain_permonth,data[0][:96]])

if __name__=="__main__":
    data=getWeatherCSV("Colorado.csv")
    data['TIMESTAMP'] = pd.to_datetime(data['TIMESTAMP'])
    data=data[(data['TIMESTAMP'].dt.day == 15) & (data['TIMESTAMP'].dt.hour == 12)]
    data=data.values.T
    temp=25.4*np.array([1.34,1.85,1.1,0.71,0.79,0.59,0.39,0.39,0.75,1.26,1.42,2.36])
    rain_permonth=np.array([])
    for index in range(4):
        rain_permonth=np.append(rain_permonth,temp)
    plt.plot(data[0][:96],rain_permonth)
    plt.plot(5+data[0][:96],data[17][:96])
    plt.xlabel('month')
    plt.show()

Q2.py

from mcm2023 import *
from Q1_SimWeather import *
'''
##################
若改变物种数量在此修改
##################
'''
# 物种数量
N=2
# 切片数
num_of_slices=48
# 初始数量
x = np.array([20,20,20,20,20])[:N]
# 种间系数
co=np.array([
    [-1,-1,1,1,1],
    [-1,-1,1,1,1],
    [1,1,-1,-1,1],
    [1,1,-1,-1,1],
    [-1,1,-1,1,-1],
])[:N,:N]
'''
##################
end
##################
'''
def func(x: list, t, b: list, a: list):
    x=x.reshape(1,x.size)
    return (x.T * (a @ (x.T) + (b.T[int(t)]).reshape(N,1))).T.flatten()

t = np.linspace(0, num_of_slices-1, num_of_slices)
t = [int(x) for x in t]
a=np.full((N,N),0.3)
for index in range(a[0].size):
    a[index][index]=0.5
a=a*co
b=np.zeros((N,num_of_slices))

# 生成随机天气
# weather=genRandomWeather(num_of_slices)

# 生成科罗拉多天气
# weather=getColoradoWeather()

# 生成恒定条件天气(slices不能太长?)
# weather=genWeather(24,1000,num_of_slices)

# 模拟干旱天气
# weather=simDroughtWeather(num_of_slices)

# 模拟一组指定的随机干旱天气
weather=np.array([[29, 27, 34, 32, 28, 28, 27, 33, 33, 29, 28, 33, 34, 28, 25, 29,
        26, 32, 31, 27, 32, 29, 30, 33, 27, 29, 25, 26, 25, 32, 33, 25,
        32, 28, 25, 33, 26, 34, 34, 30, 34, 33, 29, 30, 30, 29, 31, 31,
        32, 32, 34, 27, 28, 25, 29, 30, 28, 30, 27, 25, 26, 29, 34, 32,
        31, 34, 30, 27, 33, 27, 33, 26, 29, 31, 28, 26, 29, 33, 28, 32,
        34, 30, 30, 34, 34, 33, 32, 26, 29, 33, 27, 25, 32, 25, 31, 33],
       [38, 45, 44, 34, 40, 46, 36, 47, 35, 36, 38, 38, 40, 35, 35, 45,
        47, 47, 47, 37, 38, 35, 34, 45, 37, 47, 42, 49, 39, 47, 45, 47,
        43, 34, 47, 38, 36, 47, 39, 37, 46, 49, 47, 48, 44, 35, 47, 48,
        14,  0, 15,  1, 11,  7,  3,  4, 11, 16,  8,  2, 13,  1, 12,  5,
         2, 11, 11, 15,  5,  4,  5,  6,  3, 16, 16, 10,  9, 14, 11, 11,
        16,  9,  7,  1, 12,  0, 12, 11, 13, 14,  9,  2, 11,  9,  8,  3]])
weather=genRandomContinentalWeather(num_of_slices)
# 绘制气温与降雨量
drawWeather(t,weather)
for index in range(N):
    df=getCSV(index)
    b[index]=getb(weather[0],weather[1],
        (df[1]+df[2])/2,
        (df[3]+df[4])/2,
        (df[2]-df[1]),
        (df[4]-df[3])
    )

sol = odeint(func, x, t, args=(b, a))
print(sol)
print(calcEta(sol))

# 绘制x-t图像
for index in range(N):
    plt.plot(t, sol.T[index], label="%s"%(getCSV(index)[0]))

# for index in range(N):
#     plt.plot(weather[2], sol.T[index], label="species %d"%index)

plt.xlabel("month")
plt.ylabel("num")
plt.legend()
plt.show()

Q2_combination.py

from mcm2023 import *
from Q1_SimWeather import *
def Q2(N:int,combinations:list,getdata=0):
    # 物种数量
    # N=3
    # 切片数
    num_of_slices=96
    # 初始数量
    x = np.array([20,20,20,20,20])[:N]
    # 排列顺序
    # combinations=np.array([0,1,2,3,4])[:N]
    combinations=combinations[:N]
    # 种间系数
    co=np.array([
        [-1,-1,1,1,1],
        [-1,-1,1,1,1],
        [1,1,-1,-1,1],
        [1,1,-1,-1,1],
        [-1,1,-1,1,-1],
    ])
    # 重建种间系数
    co_temp=np.zeros((N,N))
    for row in range(N):
        for col in range(N):
            co_temp[row][col]=np.copy(co[combinations[row]][combinations[col]])
    co=np.copy(co_temp)
    # L-V模型数值求解方程
    def func(x: list, t, b: list, a: list):
        if t>=num_of_slices:
            return
        x=x.reshape(1,x.size)
        return (x.T * (a @ (x.T) + (b.T[int(t)]).reshape(N,1))).T.flatten()

    t = np.linspace(0, num_of_slices-1, num_of_slices)
    t = np.array([int(x) for x in t])
    a=np.full((N,N),0.3)
    for index in range(a[0].size):
        a[index][index]=0.5
    a=a*co
    b=np.zeros((5,num_of_slices))
    # 模拟一组指定的随机干旱天气
    # weather=np.array([[29, 27, 34, 32, 28, 28, 27, 33, 33, 29, 28, 33, 34, 28, 25, 29,
    #         26, 32, 31, 27, 32, 29, 30, 33, 27, 29, 25, 26, 25, 32, 33, 25,
    #         32, 28, 25, 33, 26, 34, 34, 30, 34, 33, 29, 30, 30, 29, 31, 31,
    #         32, 32, 34, 27, 28, 25, 29, 30, 28, 30, 27, 25, 26, 29, 34, 32,
    #         31, 34, 30, 27, 33, 27, 33, 26, 29, 31, 28, 26, 29, 33, 28, 32,
    #         34, 30, 30, 34, 34, 33, 32, 26, 29, 33, 27, 25, 32, 25, 31, 33],
    #     [38, 45, 44, 34, 40, 46, 36, 47, 35, 36, 38, 38, 40, 35, 35, 45,
    #         47, 47, 47, 37, 38, 35, 34, 45, 37, 47, 42, 49, 39, 47, 45, 47,
    #         43, 34, 47, 38, 36, 47, 39, 37, 46, 49, 47, 48, 44, 35, 47, 48,
    #         14,  0, 15,  1, 11,  7,  3,  4, 11, 16,  8,  2, 13,  1, 12,  5,
    #         2, 11, 11, 15,  5,  4,  5,  6,  3, 16, 16, 10,  9, 14, 11, 11,
    #         16,  9,  7,  1, 12,  0, 12, 11, 13, 14,  9,  2, 11,  9,  8,  3]])
    # 模拟干旱天气
    weather=simDroughtWeather(num_of_slices)
    # weather=genRandomContinentalWeather(num_of_slices)
    # 绘制气温与降雨量
    # drawWeather(t,weather)
    cnt=0
    for index in combinations:
        df=getCSV(index)
        b[cnt]=getb(weather[0],weather[1],
            (df[1]+df[2])/2,
            (df[3]+df[4])/2,
            (df[2]-df[1]),
            (df[4]-df[3])
        )
        cnt+=1
    b=b[:N]
    sol = odeint(func, x, t, args=(b, a))
    # print(sol)
    print(calcEta(sol))
    if getdata:
        return calcEta(sol)
    # 绘制x-t图像
    # for index in range(N):
    #     plt.plot(t, sol.T[index], label="%s"%(getCSV(combinations[index])[0]))

    # plt.xlabel("month")
    # plt.ylabel("num")
    # plt.legend()
    # plt.show()

if __name__=="__main__":
    str0=[]
    for index in range(5):
        str0.append(Q2(index+1,np.array([4,3,2,1,0]),1))
    print(str0)
    # Q2(5,np.array([0,1,2,3,4]))

Q3.py

from mcm2023 import *
from mpl_toolkits.mplot3d import Axes3D
def Q3(co1,co2):
    # 物种数量
    N=3
    # 切片数
    num_of_slices=48

    def func(x: list, t, b: list, a: list):
        dx0dt = x[0] * (b[0][int(t)] - a[0][0] * x[0] - a[0][1] * x[1] + a[0][2] * x[2])
        dx1dt = x[1] * (b[1][int(t)] - a[1][0] * x[0] - a[1][1] * x[1] + a[1][2] * x[2])
        dx2dt = x[2] * (b[2][int(t)] + a[2][0] * x[0] + a[2][1] * x[1] - a[2][2] * x[2])
        return [dx0dt, dx1dt, dx2dt]

    t = np.linspace(0, num_of_slices-1, num_of_slices)
    t = [int(x) for x in t]
    x0 = [10, 10, 15]

    a=np.full((N,N),0.3)
    for index in range(a[0].size):
        a[index][index]=0.5
    a*=co1
    b=np.zeros((N,num_of_slices))

    weather=genRandomWeather(num_of_slices)
    for index in range(N):
        df=getCSV(index)
        b[index]=co2*getb(weather[0],weather[1],
            (df[1]+df[2])/2,
            (df[3]+df[4])/2,
            (df[2]-df[1]),
            (df[4]-df[3])
        )

    sol = odeint(func, x0, t, args=(b, a))
    return np.average(sol.T[0])+np.average(sol.T[1])+np.average(sol.T[2])

if __name__ == "__main__":
    cnt=1
    x=np.linspace(1.01,1.20,20)
    y=np.linspace(0.99,0.80,20)
    z=np.zeros((20,20))
    for co1 in x:
        for co2 in y:
            print(cnt)
            cnt+=1
            z[int(100*(co1-1.01))][int(100*(0.99-co2))]=Q3(co1,co2)
    print(z)
    # 绘制三维热力图
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    x, y = np.meshgrid(x, y)
    heat_map = ax.plot_surface(x, y, z, cmap='viridis')
    fig.colorbar(heat_map, ax=ax, label='population sum')
    ax.set_xlabel('X/a coefficient')
    ax.set_ylabel('Y/b coefficient')
    ax.set_zlabel('Z/population sum')
    plt.show()