Search code examples
pythonclassode

AttributeError: 'float' object has no attribute 'S0'


import ODESolver
import matplotlib.pyplot as plt
import numpy as np



class Region:
    def __init__(self, region, S0, I0, R0, D0):
        self.S0 = S0
        self.I0 = I0
        self.R0 = R0
        self.D0 = D0
        self.region = region



    def set_SIRD_values(self, u, t):

        self.S = u[:,0]
        self.I = u[:,1]
        self.R = u[:,2]
        self.D = u[:,3]
        self.t = t

    def plot(self, x_label):
        plt.plot(self.t, self.S, label="Susceptible", color="blue")
        plt.plot(self.t, self.I, label="Susceptible", color="yellow")
        plt.plot(self.t, self.R, label="Susceptible", color="red")
        plt.plot(self.t, self.D, label="Susceptible", color="green")

class ProblemSIRD:
    def __init__(self, region, alpha, beta, gamma):
        self.region = region
        if isinstance(alpha, (float, int)):
            self.alpha = lambda t: alpha 
        elif callable(alpha):
            self.alpha = alpha
        self.beta = beta
        self.gamma = gamma

    def set_initial_condition(self):
        self.initial_condition = [self.region.S0, self.region.I0, self.region.R0, self.region.D0]
    def get_population(self):
        return self.region.S0 + self.region.I0 + self.region.R0 + self.region.D0
    def solution(self, u, t):
        return self.region.set_SIRD_values() 
    def __call__(self, u, t):
        S, I, R, D = u
        return [-self.alpha * S * I,self.alpha * S * I - self.beta * I - self.gamma * I,self.beta * I,self.gamma * I]

class SolverSIRD:
    def __init__(self, problem, T, dt):
        self.problem = problem
        self.T = T
        self.dt = dt
        self.total_population = ProblemSIRD.get_population(problem)

    def terminate(self,U,t,time_step):
        tol = 1e-10
        msg = 'Error in numerical method'
        assert abs(sum(U[time_step]) - self.total_population()) < tol, msg

    def solve(self, method=RungeKutta4):
        solver = method(self.problem)
        problem.set_initial_condition()
        t = np.linspace(0, self.T, self.dt)
        u, t = solver.solve(t, self.terminate)
        self.problem.solution(u, t)

U0 = [7000.0, 30.0, 0.0, 0.0]
initialP = 63

alpha = 6.5e-5
beta = 0.1/4
gamma = 0.9/4

bjorgvin = Region('Bjorgvin', U0[0], U0[1], U0[2], U0[3])
problem = ProblemSIRD(alpha, beta, gamma, bjorgvin)

solver = SolverSIRD(problem,63,64)
solver.solve(method = ODESolver.RungeKutta4)
Region.plot(x_label = bjorgvin)
plt.legend()
plt.show()

Error:

line 50, in get_population return self.region.S0 + self.region.I0 + self.region.R0 + self.region.D0

AttributeError: 'float' object has no attribute 'S0'

There might be more than one error here, but I would really appreciate if you could help me with this one. I got the same problem with the "set_initial_condition"-function. Why am I not able to use the attributes from the class Region?


Solution

  • Take a look at these lines in your code:

    class ProblemSIRD:
        def __init__(self, region, alpha, beta, gamma):
            ...
    

    The __init__ method of your class ProblemSIRD expects that the Region object is passed as first parameter. However, when instantiating the class, you pass it as last parameter.

    bjorgvin = Region('Bjorgvin', U0[0], U0[1], U0[2], U0[3])
    problem = ProblemSIRD(alpha, beta, gamma, bjorgvin)
    

    Rewriting the line as problem = ProblemSIRD(bjorgvin, alpha, beta, gamma) should solve this problem.