1

My final project is develop a simulation of the new Omicron variable of Covid-19 in my state, using the SEIR model and Java, so, I was read some articles about how the SEIR model works and I have the equations needed to do it, are the followings:

enter image description here

enter image description here

  • N: Total of population (4,132,000)
  • S: Susceptible (Non-infected)
  • E: Exposed (Infected but not infectious yet)
  • I: Infected (Infected and infectious, I'm using 1)
  • R: Recovered or Dead
  • µ: Mortality rate (0.18)
  • β: Infection rate (for my State, I'm using 0.5)
  • ν: Vaccinated population (56.7%)
  • σ: Contagious rate (also named as R0, for Covid-19 I'm using 2.33, 2.6 and 5.0)
  • Y: Recovered rate (for my state, I'm using 93%)

So, I try to put these variables into my code and it didn't work, here is my code:

package project;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class SEIR {

    int totalDias = 200; // Days to simulate
    int N = 4132000; // Population
    // SEIR model variables
    int I0 = 1; // Infected initial
    int E0 = 1; // Exposed initial
    double beta = 0.5; // Infection rate
    double gamma = 1.0/10.0; // Recovery time
    double a = 1.0/2.0; // Incubation period
    double mi = 0.18; // Death rate
    double ipsilon = 0.567; // Vaccinated population
    double gamma2 = 0.93; // Recovered rate
    double sigma = 2.33; // R0, it can change to 2.6 or 5.0
    List<Double> S = new ArrayList<>();
    List<Double> E = new ArrayList<>();
    List<Double> I = new ArrayList<>();
    List<Double> R = new ArrayList<>();

    private void iniciarSimulacionSEIR() {
        XYSeries lineaS = new XYSeries("S");
        XYSeries lineaE = new XYSeries("E");
        XYSeries lineaI = new XYSeries("I");
        XYSeries lineaR = new XYSeries("R");
        final int R0 = 0; // Recovered initial
        final int S0 = N - E0 - I0 - R0; // Susceptible population (population - Exposed - Infected - Recovered)

        // Adding the initial values
        S.add((double) S0);
        E.add((double) E0);
        I.add((double) I0);
        R.add((double) R0);

        for (int dia=1; dia<totalDias+1; dia++) {
            double[] ecuaciones = calculo1(dia);
            S.add(ecuaciones[0]);
            E.add(ecuaciones[1]);
            I.add(ecuaciones[2]);
            R.add(ecuaciones[3]);
            // Adding the values for S, E, I and R on each of the lines to be plotted
            lineaS.add(dia, S.get(dia));
            lineaE.add(dia, E.get(dia));
            lineaI.add(dia, I.get(dia));
            lineaR.add(dia, R.get(dia));
            // Printing the values for S, E, I and R day by day
            System.out.println("S: "+S.get(dia)+" in day: "+dia);
            System.out.println("E: "+E.get(dia)+" in day: "+dia);
            System.out.println("I: "+I.get(dia)+" in day: "+dia);
            System.out.println("R: "+R.get(dia)+" in day: "+dia+"\n");
        }

        // The collection for our 4 lines to graph
        XYSeriesCollection datacol = new XYSeriesCollection();
        datacol.addSeries(lineaS);
        datacol.addSeries(lineaE);
        datacol.addSeries(lineaI);
        datacol.addSeries(lineaR);

        JFreeChart xyLineChart = ChartFactory.createXYLineChart(
                "Simulación de la variable ómicron en Oaxaca", // Title
                "Días", // Data tag
                "Población", // Values tag
                datacol, // Data
                PlotOrientation.VERTICAL, // orientation
                true, // Include legend
                true, // Include tooltips
                false // urls
        );

        XYPlot plot = xyLineChart.getXYPlot();

        // This part adds color and size for each line
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        renderer.setSeriesPaint(0, Color.RED);
        renderer.setSeriesPaint(1, Color.GREEN);
        renderer.setSeriesPaint(2, Color.YELLOW);
        renderer.setSeriesPaint(3, Color.BLUE);
        renderer.setSeriesStroke(0, new BasicStroke(2.0f));
        renderer.setSeriesStroke(1, new BasicStroke(2.0f));
        renderer.setSeriesStroke(2, new BasicStroke(2.0f));
        renderer.setSeriesStroke(3, new BasicStroke(2.0f));
        plot.setRenderer(renderer);

        ChartPanel panel = new ChartPanel(xyLineChart);

        // Create the frame
        JFrame ventana = new JFrame("Simulador");
        ventana.setVisible(true);
        ventana.setSize(800, 600);
        ventana.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ventana.add(panel);
    }

    private double[] calculoSEIR(int dia) {
        dia = dia - 1;
        double dS = (beta * S.get(dia) * I.get(dia)) / N;
        double newS = S.get(dia) - (dS);
        double newE = E.get(dia) + (dS - (a * E.get(dia)));
        double newI = I.get(dia) + ((a * E.get(dia)) - (gamma * I.get(dia)));
        double newR = R.get(dia) + (gamma * I.get(dia));
        return new double[] {newS, newE, newI, newR};
    }

    private double[] calculo1(int dia) {
        dia = dia -1;

        // These variables are just for shortening the 4 equations of the model
        double SIN = (S.get(dia)*I.get(dia)) / N;
        double VS = ipsilon*S.get(dia);
        // 1st equation (dS/dt)
        double dS = mi*(N-S.get(dia)) - beta * SIN - VS;
        // 2nd equation (dE/dt)
        double dE = (beta * SIN) - (mi+sigma)* E.get(dia);
        // 3rd equation (dI/dt)
        double dI = sigma*E.get(dia)-(gamma2+mi)*I.get(dia);
        // 4th equation (dR/dt)
        double dR = gamma2*I.get(dia)-mi*R.get(dia)+VS;
        return new double[] {dS, dE, dI, dR};
    }

    public SEIR() {
        iniciarSimulacionSEIR();
    }

    public static void main(String[] args) {
        new SEIR();
    }
}

It doesn't work when I compile it, here's an image of my result: enter image description here

Luckily, I found this question in StackOverflow which was very helpful, I made some adjustments to use my own data and modify the method calling in line 56, as the follow: I just have to change this line (inside the for loop):

double[] ecuaciones = calculo1(dia);

for this one:

double[] ecuaciones = calculoSEIR(dia);

And the result is the following: enter image description here

So, it works, but I don't know properly how it works and I'm not using the original model, instead of this one I'm using the model and equations (also a SEIR model) that I found in the other question and that's how I finally be able to make it work, I'll really apreciate if someone can help me with this, there is some way I can use the proposed model at the first? or it's better to me just not touch it anymore and leave it like this? Also, my teacher asked me for 2 more simulation models apart from the SEIR, could someone recommend me some that is not so complicated to implement in Java?

Thank you for reading all!!

Orlando Lucero
  • 323
  • 2
  • 7
  • 1
    From the information posted we can conclude that the problem is in **calculating** the data, and not in the view. If that is the case please remove all the code related to displaying the data to make your code more of an [mre]. This will make helping you much easier, avoiding the dependency o an external library. In general, it is a good practice to separate the data (model) from the display (view). Also consider names and comments in English to make the code easier to follow. – c0der Jan 05 '22 at 06:14
  • Yes, my problem is in the data and not for the view because when I call the method calculoSEIR() instead of calculo1() it works perfectly, and that's the reason of I asked here, I'm not understanding well how the SEIR model works and how I should enter my data for it to work properly. I'll try to reduce the equations and simplify my example, thank you. I added some comments in english, I apologize for not did it before. – Orlando Lucero Jan 05 '22 at 07:02
  • See [_Compartmental models in epidemiology_](https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology). Note that SEIR does not model vaccination. – trashgod Jan 06 '22 at 00:47
  • See [_A Simulation of a COVID-19 Epidemic Based on a Deterministic SEIR Model_](https://www.frontiersin.org/articles/10.3389/fpubh.2020.00230/full). – trashgod Jan 08 '22 at 17:29
  • See [_SEIR Modeling of the Italian Epidemic of SARS-CoV-2 Using Computational Swarm Intelligence_](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC7277829/). – trashgod Jan 08 '22 at 17:35

1 Answers1

1

MRE is a very useful techniques. Not only it makes helping much easier, but it is also a powerful debugging tool. While preparing one, you are likely to find the problem or at least be able to pinpoint it. To make the code more of an mre let's remove the parts of it that displays the results because it works fine and requires dependency on an external library.

import java.util.ArrayList;
import java.util.List;

public class SEIR {

    int totalDias = 200; // Days to simulate
    int N = 4132000; // Population
    // SEIR model variables
    int I0 = 1; // Infected initial
    int E0 = 1; // Exposed initial
    double beta = 0.5; // Infection rate
    double gamma = 1.0/10.0; // Recovery time
    double a = 1.0/2.0; // Incubation period
    double mi = 0.18; // Death rate
    double ipsilon = 0.567; // Vaccinated population
    double gamma2 = 0.93; // Recovered rate
    double sigma = 2.33; // R0, it can change to 2.6 or 5.0
    List<Double> S = new ArrayList<>();
    List<Double> E = new ArrayList<>();
    List<Double> I = new ArrayList<>();
    List<Double> R = new ArrayList<>();

    private void iniciarSimulacionSEIR() {
        final int R0 = 0;
        final int S0 = N - E0 - I0 - R0; // Susceptible population (population - Exposed - Infected - Recovered)

        S.add((double) S0);
        E.add((double) E0);
        I.add((double) I0);
        R.add((double) R0);

        for (int dia=1; dia<totalDias+1; dia++) {
            double[] ecuaciones = calculo1(dia);//calculoSEIR(dia); 
            S.add(ecuaciones[0]);
            E.add(ecuaciones[1]);
            I.add(ecuaciones[2]);
            R.add(ecuaciones[3]);
                System.out.println("S: "+S.get(dia)+" en el día: "+dia);
                System.out.println("E: "+E.get(dia)+" en el día: "+dia);
                System.out.println("I: "+I.get(dia)+" en el día: "+dia);
                System.out.println("R: "+R.get(dia)+" en el día: "+dia+"\n");
        }

    }

    private double[] calculoSEIR(int dia) {
        dia = dia - 1;
        double dS = beta * S.get(dia) * I.get(dia) / N;
        double newS = S.get(dia) - dS;
        double newE = E.get(dia) + (dS - a * E.get(dia));
        double newI = I.get(dia) + (a * E.get(dia) - gamma * I.get(dia));
        double newR = R.get(dia) + gamma * I.get(dia);
        return new double[] {newS, newE, newI, newR};
    }

    private double[] calculo1(int dia) {
        dia = dia -1;

        double SIN = S.get(dia) * I.get(dia) / N;
        double VS = ipsilon*S.get(dia);
        //double dS = mi*(N-S.get(dia)) - beta * ((S.get(dia)*I.get(dia))/N) - ipsilon*S.get(dia);
        double dS = mi*(N-S.get(dia)) - beta * SIN - VS;
        //double dE = beta * ((S.get(dia)*I.get(dia))/N) - (mi+sigma) * E.get(dia);
        double dE = beta * SIN - (mi+sigma)* E.get(dia);
        //double dI = sigma * E.get(dia) - (gamma+mi) * I.get(dia);
        double dI = sigma*E.get(dia)-(gamma2+mi)*I.get(dia);
        //double dR = gamma * I.get(dia) - mi * R.get(dia) + ipsilon * S.get(dia);
        double dR = gamma2*I.get(dia)-mi*R.get(dia)+VS;
        return new double[] {dS, dE, dI, dR};
    }

    public SEIR() {
        iniciarSimulacionSEIR();
    }

    public static void main(String[] args) {
        new SEIR();
    }
}

Running this mre quickly reveals a problem that starts at dia=31:

S: -Infinity en el día: 31
E: Infinity en el día: 31
I: -1.543349343128143E192 en el día: 31
R: 3.755704195509258E191 en el día: 31

Basic printout (or better using a debuger) reveals that
S.get(30) = 6.623816923296751E191 and I.get(dia) = 2.6314568343148793E121

so S.get(30)*I.get(30) is bigger than the largest number that can be represented by Double which is Double.MAX_VALUE = 1.7976931348623157E308 hence the infinity.
TODO : if the values are what should be expected use BigDecimal, or else fix the model.

c0der
  • 18,467
  • 6
  • 33
  • 65
  • 1
    A [mre] for the win! As `beta < 1`, it's often possible to rearrange things to avoid overflow, as in the SEIR example cited. – trashgod Jan 06 '22 at 00:55