11import numpy as np
2- from scipy .integrate import odeint
3- from scipy .ndimage import label
4- from scipy .optimize import curve_fit
5- from scipy .stats import kstest
62import matplotlib .pyplot as plt
73from typing import Tuple , List , Dict , Optional
4+ from scipy .integrate import solve_ivp
5+ from scipy .integrate import odeint
86
97class MeanFieldModel :
108 """
119 Mean-field (non-spatial) predator-prey model.
10+
11+ Equations:
12+ dR/dt = R * (b - d_r - c*C - e*R)
13+ dC/dt = C * (a*R - d_c - q*C)
14+
15+ where:
16+ R: Prey population density
17+ C: Predator population density
18+ b: Prey birth rate
19+ d_r: Prey death rate
20+ c: Consumption rate of prey by predators
21+ e: Intraspecific competition among prey
22+ a: Conversion efficiency of prey into predator offspring
23+ d_c: Predator death rate
24+ q: Intraspecific competition among predators
1225 """
1326
14- def __init__ (self , birth : float , consumption : float , predator_death : float ):
27+ def __init__ (self ,
28+ birth : float = 0.2 ,
29+ consumption : float = 0.8 ,
30+ predator_death : float = 0.045 ,
31+ conversion : float = 1.0 ,
32+ prey_competition : float = 0.1 ,
33+ predator_competition :float = 0.05 ):
1534 """
1635 Initialize the mean-field model with given parameters.
1736 Args:
1837 birth (float): Prey birth rate (b)
19- consumption (float): predator consumption rate (c)
20- predator_death (float): predator death rat (d_c)
38+ consumption (float): Consumption rate of prey by predators (c)
39+ predator_death (float): Predator death rate (d_c)
40+ conversion (float): Conversion efficiency of prey into predator offspring (a)
41+ prey_competition (float): Intraspecific competition among prey (e)
42+ predator_competition (float): Intraspecific competition among predators (q)
2143 """
44+ self .birth = birth
45+ self .consumption = consumption
46+ self .predator_death = predator_death
47+ self .conversion = conversion
48+ self .pred_benifit = self .consumption * self .conversion
49+ self .prey_competition = prey_competition
50+ self .predator_competition = predator_competition
2251
23- def ode_system (self , Z : np .ndarray , t : float , prey_death : float )-> List [ float ] :
52+ def ode_system (self , Z : np .ndarray , t : float , prey_death : float )-> list :
2453 """
25- Mean-field ODE system for predator prey dynamics
26-
27- Args:
28- Z (np.ndarray): _description_
29- t (float): _description_
30- prey_death (float): _description_
31-
32- Returns:
33- List[float]: _description_
54+ Mean-field ODE system for predator prey dynamics.
3455 """
35- pass
56+ R , C = Z
57+
58+ R = max (R , 0 )
59+ C = max (C ,0 )
60+
61+ # Net prey growth rate
62+ r = self .birth - prey_death
63+
64+ # Prey dynamics: growth - predation - competition
65+ dR = R * (r - self .consumption * C - self .prey_competition * R )
66+
67+ # Predator dynamics: growth from predation - death - competition
68+ dC = C * (self .conversion * self .consumption * R - self .predator_death - self .predator_competition * C )
69+
70+ return [dR , dC ]
71+
3672
37- def solve (self , prey_death : float , Z0 : Tuple [ float , float ] , t_max : float , n_points : int )-> Tuple [np .ndarray , np .ndarray ]:
73+ def solve (self , prey_death : float = 0.5 , R0 : float = 0.5 , Z0 : float = 0.2 , t_max : float = 500 , n_points : int = 1000 )-> Tuple [np .ndarray , np .ndarray ]:
3874 """
3975 Solve the mean-field ODE system.
4076
@@ -47,28 +83,97 @@ def solve(self, prey_death: float, Z0: Tuple[float, float], t_max: float, n_poin
4783 Returns:
4884 Tuple[np.ndarray, np.ndarray]: Time points and solution array
4985 """
50- pass
86+ t = np .linspace (0 , t_max , n_points )
87+ Z0 = [R0 , Z0 ]
88+
89+ sol = odeint (self .ode_system , Z0 , t , args = (prey_death ,))
90+
91+ return t , sol
5192
5293 def equilibrium (self , prey_death : float )-> Tuple [float , float ]:
5394 """
54- Calculate the equilibrium point of the system.
95+ Calculate the equilibrium densities of the system.
5596
5697 Args:
5798 prey_death (float): Prey death rate (d)
5899
59100 Returns:
60101 Tuple[float, float]: Equilibrium populations (prey, predator)
61102 """
62- pass
103+ r = self .birth - prey_death
104+ c = self .consumption
105+ a = self .pred_benifit
106+ e = self .prey_competition
107+ q = self .predator_competition
108+ d_c = self .predator_death
109+
110+ if r <= 0 :
111+ return (0.0 , 0.0 )
112+
113+ R_prey = r / e
114+
115+ # Check if predator can invade
116+ predator_invasion_fitness = a * R_prey - d_c
117+ if predator_invasion_fitness <= 0 :
118+ return (R_prey , 0.0 ) # Predator cannot persist
119+
120+ # Coexistence equilibrium
121+ R_n = r * q + d_c * c
122+ R_d = c * a + e * q
123+
124+ if R_d <= 0 :
125+ return (R_prey , 0.0 )
126+
127+ R_star = R_n / R_d
128+ C_star = (a * R_star - d_c ) / q
129+
130+ if R_star < 0 or C_star < 0 :
131+ if r > 0 :
132+ return (R_prey , 0.0 )
133+ else :
134+ return (0.0 , 0.0 )
135+
136+ return (R_star , C_star )
63137
64- def sweep_death_rate (self , d_r_values : np . ndarray , t_equilibrium : float ) -> Dict [ str , np . ndarray ]:
138+ def equilibrium_numerical (self , prey_death : float , t_max : float = 1000 ) -> Tuple [ float , float ]:
65139 """
66- Sweep prey death rate and record equilibrium densities .
140+ Find equilibrium densities numerically by solving ODEs over a long time .
67141 """
68- pass
142+ t , Z = self .solve (prey_death = prey_death , t_max = t_max )
143+ R_eq = max (0 , np .mean (Z [- 100 :, 0 ]))
144+ C_eq = max (0 , np .mean (Z [- 100 :, 1 ]))
145+ return (R_eq , C_eq )
69146
70- def nullclines (self , prey_death : float , Z_r_range : np . ndarray ) -> Dict [str , np .ndarray ]:
147+ def sweep_death_rate (self , d_r_values : np . ndarray , method : str = 'analytical' ) -> Dict [str , np .ndarray ]:
71148 """
72- Compute nullclines for phase portrait.
149+ Sweep prey death rate and record equilibrium densities.
73150 """
74- pass
151+ n = len (d_r_values )
152+ R_eq = np .zeros (n )
153+ C_eq = np .zeros (n )
154+
155+ for i , d_r in enumerate (d_r_values ):
156+ if method == 'analytical' :
157+ R_eq [i ], C_eq [i ] = self .equilibrium (d_r )
158+ else :
159+ R_eq [i ], C_eq [i ] = self .equilibrium_numerical (d_r )
160+
161+ return {'d_r' : d_r_values , 'R_eq' : R_eq , 'C_eq' : C_eq , 'net_growth' : self .birth - d_r_values }
162+
163+
164+
165+ # FIXME: Add plotting utilities
166+
167+
168+ if __name__ == '__main__' :
169+ print ("Mean-Field Model Module" )
170+ mf = MeanFieldModel ()
171+
172+ print ('Model Parameters:' )
173+ print (f'Birth rate: { mf .birth } ' )
174+ print (f'Consumption rate: { mf .consumption } ' )
175+ print (f'Predator death rate: { mf .predator_death } ' )
176+ print (f'Conversion efficiency: { mf .conversion } ' )
177+ print (f'Prey competition: { mf .prey_competition } ' )
178+ print (f'Predator competition: { mf .predator_competition } ' )
179+
0 commit comments