Diese Seite ist noch in Bearbeitung, und wird noch komplett geändert

Gruppenseite - VT Bearbeiten

Diese Seite enthält die gesammelten Materialien der Gruppe 10 - VT für die Portfolioprüfung.

Teilnehmer-innen Bearbeiten

  • Toker, Merve
  • Vatter, Melanie

Ziel der Veranstaltung Bearbeiten

Das Modul M11: Entwicklung der Mathematik in Längs- und Querschnitten unterteilt in zwei Bereiche:

  • diskrete Prozesse (Herr Niehaus)
  • Kontinuierlichen Diffusionsprozesse (Frau Hundertmark)

Beide dienen der Modellierung der COVID-19-Pandemie.

In beiden Bereichen wurden zeitliche und räumliche Betrachtungen vorgenommen.

Für beide Teilbereiche sollte während eines Lehrveranstaltung Aufgaben bearbeitet werden.

Die Aufgaben zu den diskreten Prozessen sind hier zu finden[1].

Die detaillierten Aufgabenstellungen zu den kontinuierlichen Diffusionsprozessen sind hier einzusehen [2].


In einigen Beispielen werden Beispielrechnungen für die Stadt Mainz gemacht. Hierbei ist zu beachten, dass wir nur das "Zentrum" der Stadt betrachten, also nur die Stadtteile: Altstadt, Neustadt, Oberstadt und Hartenberg-Münchfeld. Wenn also im Folgenden Einwohnerzahlen, Infektionsraten oder Bevölkerungsdichten genannt werden, beziehen sich diese nur auf die soeben genannten Stadtteile.

Diskrete Diffusionsprozesse (Niehaus) Bearbeiten

SIR Modell Bearbeiten

Die erste Aufgabe bestand darin, einen Zusammenhang zwischen S, I und R (Susceptible, Infected und Recovered) darzustellen. Hierfür haben wir das SIR Modell gewählt. Um die Entwicklung der Infektionszahlen am Beispiel der Stadt Mainz darzustellen wird das SIR Modell über Funktionen angewandt.

Dafür wurden zuerst Anfangswerte generiert. Dabei wurde Bevölkerung B, die Basisinfektionsrate beta, die Genesungsrate gamma und die Todesrate d definiert. Dabei besteht die Bevölkerung B nur aus zwei Drittel der gesamten Mainzer Bevölkerung dar. Denn bei einer Epidemie geht man meistens davon aus, dass sich nur zwei Drittel aller Menschen infizieren (können).

Des Weiteren werden die Anzahl der Tage, für die das Modell laufen soll generiert.

Anschließend wurden die Anfangswerte der Funktionen und die Funktionen für Folgetage für S (Susceptible), I (Infected), R (Removed) und kI (kummulierte Infizierte) generiert.

Zum Schluss wurden die Funktionen geplottet und wir erhielten das Bild, was unter den Implementierungen von Octave zu sehen sind.


  B = 141600;    #Kapazitaetsgrenze, 2/3 der Mainzer Bevölkerung (212400)
  beta = 0.29;   #Basisinfektionsrate (die Rate des exponentiellen Wachstums am Anfang der Pandemie)
  gamma = 0.1;   #Genesungsrate (Wechselrate der Infizierten in die Gruppe der Genesenen)
  d = 0.003;     #Todesrate
  N_t=125;
  t=linspace(0,N_t,N_t+1);
  S(1)=B-I(1);
  I(1)=50;       #Am Anfang der Modellierung gibt es 50 Infizierte in Mainz 
  R(1)=0;        #Am Anfang der Pandemie ist noch niemand Genesen
  for n=1:N_t;
  S(n+1)=S(n)-(beta/B)*S(n)*I(n);
  I(n+1)=I(n)+(beta/B)*S(n)*I(n)-gamma*I(n);
  R(n+1)=R(n)+gamma*I(n)-d*I(n);
  D(n+1)=d*I(n);
  kI(n+1)=I(n+1)+R(n+1)+D(n+1);
  endfor
  hold on
  plot(t,S,'b');
  plot(t,I,'m');
  plot(t,R,'g');
  plot(t,D,'c');
  plot(t,kI,'r');
  axis([0 130 0 142000]);
  legend("S","I","R","D" "kI","location","east")
  hold off

 

Beim Plot der Inzizierten entstand eine Glockenkurve mit dem Höhepunkt nach ca. 48 Tagen. Das heißt, dass nach 48 Tagen die Infektionen zurück gehen und sich immer weniger Menschen infizieren. Die Infektion wäre nach etwa 120 Tagen überstanden.

Das Modell geht davon aus, dass die Menschen nach einer überstandenen Infektion immun gegenüber des Virus sind.

SIR modifiziert Bearbeiten

Dies ist aber in der Realität nicht der Fall. Es sind über die Corona-Infektion noch keine Langzeitstudien bekannt, allerdings sagt man pauschal, dass man wenn man eine Infizierung überstanden hat, man etwa ein halbes Jahr (ca. 183 Tage) immun ist. Daher haben wir das SIR nochmal neu modelliert, mit der Annahme, dass die Genesenen nach ca. 183 Tagen wieder zurück in die Gruppe der Anfälligen wechseln. Dabei wird unsere neue Kurve für R nicht mehr die kummulierten Infizierten anzeigen, da für die Berechnung der S, immer die R der 183 Tage vorher abgezogen werden müssen.

Der Code dafür sieht nun folgendermaßen aus:

  for n=1:N_t;
  S(n+1)=S(n)-(beta/B)*S(n)*I(n);
  I(n+1)=I(n)+(beta/B)*S(n)*I(n)-gamma*I(n);
  R(n+1)=R(n)+gamma*I(n)-d*I(n);
  kI(n+1)=I(n+1)+R(n+1);
   if n>183 && S(n)+R(n-183)<=B && R(n)-R(n-183)>=0; #Bedingung benötigt da sonst Modell negative Werte bekommt 
   S(n+1)=S(n)+R(n-183)-(beta/B)*S(n)*I(n);
   I(n+1)=I(n)+(beta/B)*S(n)*I(n)-gamma*I(n);
   R(n+1)= R(n)-R(n-183)+gamma*I(n)-d*I(n);
   endif
 
  endfor

Nahm man, wie bei dem ursprünglichen SIR-Modell an, dass nach einer Infektion eine vollständige Immunisierung stattfindet, war die Infektion nach etwa 120 Tagen überstanden. Wenn man nun beachtet, dass man nach einem halben Jahr erneut wieder infiziert werden kann, dauert die Pandemie laut diesem Modell nach etwa 6000 Tagen erst überstanden (also erst nach etwa 26 Jahren und 4 Monaten, Ende Juli 2036).

Hoffen wir mal, dass die Modellierung nicht wahr wird.

 

SIRV-Modell Bearbeiten

Des Weiteren werden seit Dezember 2020 Menschen gegen das Corona-Virus geimpft. Da man davon ausgehen kann, dass die Impfungen die Pandemie schwächen, haben wir zusätzlich eine Gruppe V für Vaccinated (geimpft) angelegt. Um diese zu implementierten waren einige Vorüberlegungen notwendig

  • Startdatum Impfungen + 14 Tage (Wirkung)
  • Impfquote

Die Impfungen starteten am Tag 305 unseres SIR-Modells, zum ersten Mal waren am 15.01.21 Menschen vollständig geimpft, mit der 14-Tage Wirkungszeit ist also unser erster Tag der Auswirkungen der Impfung der 29.01.21 (Tag 339)

Wie berechnet man die Impfquote?

Die Zahlen der Impfungen in Deutschland wurden vom Robert-Koch-Institut zur Verfügung gestellt. Diese haben wir uns als Graph ausgeben lassen:

 

Anhand der ersten und letzten bereitgestellten Zahl des RKI haben wir eine Exponentialfunktion berechnet (siehe blauer Graph), die den Daten ähneln sollte. Anfang und Endpunkt waren zwar gleich, die anderen Punkte aber eher weniger. Daher haben wir uns dazu entschieden die Funktion der Impfungen zu splitten. Wie auf dem obigen Bild gut zu erkennen ist, ähnelt der Anfang des Graphen eher einer linearen Funktion und wird erst zum Ende hin ähnlich einer Exponentialfunktion.

So haben wir die Werte aufgeteilt in die ersten 103 Tage der Imfpungen (lineare Funktion) und die danach. Dafür haben wir die Werte aber erstmal für die Stadt Mainz anteilsmäßig runtergerechnet:

Anzahl_Impfungen_Mainz = Anzahl_Impfungen Deutschland : 83 Mio. x 212400

Für die ersten 103 Tage der Impfung ergab sich folgendes Diagramm, für welches wir Excel die Lineare Funktion haben ausrechnen lassen:

 

Anschließend haben wir für die restliche Funktion die Wachstumsrate selbst bestimmt durch den Tag 104 und den letzten gegeben Tag. Wir kamen auf eine Wachstumsrate von delta=0.027

Unsere Implementierung sah dann folgendermaßen aus:

  B = 141600;    #Kapazitaetsgrenze, 2/3 der Mainzer Bevoelkerung (212400)
  beta = 0.29;          #Basisinfektionsrate- die Rate des exponenziellen Wachstums am Anfang der Pandemie
  gamma = 0.1;         #Genesungsrate
  d = 0.003;             #Todesrate
  delta=0.027;
  N_t=700;
  t=linspace(0,N_t,N_t+1);
  S(1)=B-I(1);
  I(1)=5; 
  R(1)=0;
  V(1)=0;
  V(339)=1.56;
  for n=1:N_t;
  S(n+1)=S(n)-(beta/B)*S(n)*I(n);
  I(n+1)=I(n)+(beta/B)*S(n)*I(n)-gamma*I(n);
  R(n+1)=R(n)+gamma*I(n)-d*I(n);
  D(n+1)=d*I(n);
  V(n+1)=V(n);


  if n>183 && n<=339 && S(n)+R(n-183)<=B && R(n)-R(n-183)>=0;
  S(n+1)=S(n)+R(n-183)-(beta/B)*S(n)*I(n);
  I(n+1)=I(n)+(beta/B)*S(n)*I(n)-gamma*I(n);
  R(n+1)= R(n)-R(n-183)+gamma*I(n)-d*I(n);
  D(n+1)=d*I(n);
  V(n+1)=V(n);
  endif


  if n>339 && n<=443 && S(n)+R(n-183)<=B && R(n)-R(n-183)>=0;
  S(n+1)=S(n)+R(n-183)-V(n)-(beta/B)*S(n)*I(n);
  I(n+1)=I(n)+(beta/B)*S(n)*I(n)-gamma*I(n);
  R(n+1)=R(n)-R(n-183)+gamma*I(n)-d*I(n);
  D(n+1)=d*I(n);
  V(n+1)=V(n)+141.89;
  endif
  if n>443 && n<=N_t && S(n)+R(n-183)<=B && R(n)-R(n-183)>=0;
  S(n+1)=S(n)+R(n-183)-V(n)-(beta/B)*S(n)*I(n);
  I(n+1)=I(n)+(beta/B)*S(n)*I(n)-gamma*I(n);
  R(n+1)=R(n)-R(n-183)+gamma*I(n)-d*I(n);
  D(n+1)=d*I(n);
  V(n+1)=V(n)+delta*(B-V(n)); 

Graphische Darstellung  

Man kann sehen, dass die Impfung in unserem Modell positive Auswirkungen hat. Denn die Pandemie dauert "nur" noch 500 Tage. Das heißt die Pandemie wäre am 9.Juli 2021 vorbei. Hoffen können wir ja mal....

Verbesserungsideen Bearbeiten

  • Wäre die Infektionsrate kleiner gewählt worden, wäre der Effekt der Immunisierungsaufhebung deutlicher geworden
  • Man könnte zusätzlich noch eine Slowdownfunktion (Kontakbeschränkungen, Maskenpflicht, Aufhebungen etc.) einbringen

SIR-Modell mit Bewegung Bearbeiten

Diese Modellierung basiert auf den Implementierungen der Gruppe 6.

Das soeben vorgeführte SIR-Modell ist statisch. Das heißt, es findet keine Bewegung statt und es interessiert auch nicht, wo die Menschen sind. 1 Infizierter steckt im Schnitt während seiner Krankheit 2,9 weitere Menschen an (beta:gamma=2,9) egal wo sich diese befinden.

Wir wollen uns das Ganze jetzt einmal mit möglichen Bewegungen ansehen. Damit die Zahlen nicht so groß werden, teilen wir die Bevölkerungszahl durch tausend. Somit müssen die Ergebnisse der Modellierung am Ende mit Tausend multipliziert werden um realistische Werte zu betrachten. Bei diesem Modell, haben wir zur Vereinfachung die Todesrate nicht beachtet.

  B = 2/3*212.4;    #Kapazitaetsgrenze, 2/3 der Mainzer Bevölkerung
  beta = 0.29;      #Basisinfektionsrate- die Rate des exponenziellen Wachstums am Anfang der Pandemie
  gamma = 0.1;      #Genesungsrate
  T = 130;          #Anzahl der Tage
  dt = [1:T];  

Erstellung Schachbrettmuster Bearbeiten

Um eine räumliche Modellierung erstellen zu können, erstellen wir zuerst ein Schachbrettmuster. Also ein Gitter, auf dem Menschen verteilt sind.

  xend    = 12; %in km    #Seitenlänge Schachbrett 11km
  yend    = 10; %in km    #Seitenlänge Schachbrett 9km da erst ab 1 begonnen wird
  X       = 12 ; 
  hx      = 1;
  hy      = hx;
  Y       = 10;
  h       = hx;
  [x,y]   = meshgrid(1:hx:12, 1:hy:10);
  q = 3/4;                #Anteil der pro Zeitschritt von einer Zelle in benachbarte Zellen der Moore-Matrix wandert

Zusätzlich werden Matrizen erstellt, in denen später die Werte für S, I und R gespeichert werden können. Da wir noch keine Funktionen erstellt haben, sind diese zur Zeit alle noch mit  -en gefüllt:

  S = zeros(Y,X,T);         #Verteilung der Gesamtbevölkerung Bd auf dem Schachbrett (Susceptible)
  I = zeros(Y,X,T);         #Infected
  R = zeros(Y,X,T);         #Recovered
Bevölkerungsmatrix Bearbeiten

Des Weiteren wird eine Bevölkerungsmatrix erstellt, die anschließend auf dem Schachbrett verteilt wird. Die Bevölkerungsmatrix ist entstanden aus der Bevölkerungsdichte pro Quadratmeter in den einzelnen Stadteilen. Auch bei diesen Zahlen wird in Tausendsteln gearbeitet, da die exakten Zahlen von Octave aufgrund der Größe nicht berechnet werden konnten.

Die Bevölkerungsmatrix ist folgendermaßen entstanden:

 

Die Bevölkerungsmatrix in Octave sah dann wie folgt aus:

  function val = Bd(x,y);
  # Leute pro qkm * 1000
  density = [  2 2	8 8	7 7	4 3.5 3.5 1 1;
               2 2	8 8	7 4 4 3.5 3.5 1 1;
               2 2	2 5	4 4	4 1.1 1.1 1 1;
               3 3	5 5	5 2	2 1.1 1.1 1 1;
               3 3	3 3	2 2	2 1.1 1.1 1.1 1;
               3 3	3 2	2 2	2 1.1 1.1 1.1 1.1;
              1.5 1.5	1.5	1 1	1.5	2.0	2.0 1.1 1.1 1.1;
              1.5 1.5 1.5 1.0 2.5 1.5 0.6 0.6 0.6 0.6 0.6;
              1.5 1.5 1.5 1.5 2.5 1.5 0.6 0.6 0.6 0.6 0.6;
              ];
   val = density(x,y);
   endfunction


Bestimmt man anschließend, dass alle sich in der Matrix Bd(x,y) befindlichen Menschen Susceptible sind, kann man sich das Graphisch wie folgt ausgeben lassen:

  for i=1:X;
  for j=1:Y;
   S(j,i,1) = Bd(j,i);
  endfor
  endfor
  S(:,:,1)=flipud(S(:,:,1));
  #plot Succeptible Startkonfiguration
  figure(1)
  surfc(S(:,:,1))
  xlabel('x-Achse')
  ylabel('y-Achse')
  colormap ("jet")
  colorbar
  axis ([1 xend 1 yend 0 max(max(S(:,:,1)))])
  view(0,90)
  title(["Bevoelkerungsmatrix"])

Entweder 1-Dimensional:   oder 3-Dimensional:  

Die Colorbar an den Seiten gibt an wie viele Einwohner pro Quadratkilometer sind. Die Zahl muss man für die Realität noch mit 1000 multiplizieren.

Infizierte Bearbeiten

Anschließend platzieren wir die ersten Infizierten. Hierfür arbeiten wir wieder in Tausendstel und setzen an drei Orten Infizierte die wir auch von den Susceptible/Anfälligen abziehen


   I(5,8,1) = 5/1000;  #5 Infizierte in Hartenberg (Bsp. Schule)
   S(5,8,1) = S(5,8,1)-I(5,8,1);
   I(6,9,1) = 11/1000; #11 in Altstadt (Bsp. Einkaufszentrum)
   S(6,9,1) = S(6,9,1)-I(6,9,1);
   I(8,4,1) = 9/1000; # 9 Infizierte in Bretzenheim (Bsp. Bushaltestelle)
   S(8,4,1) = S(8,4,1) - I(8,4,1);

Transportprozess Bearbeiten

Moore-Matrix Bearbeiten

Als nächstes werden anhand der Moore-Nachbarschaft eine Matrix erstellen, welche die Anzahl der nächsten Nachbarn enthält.

"Die Moore-Nachbarschaft ist eine Nachbarschaftsbeziehung in einem quadratischen Raster. Alle Flächen, welche mindestens eine Ecke mit der Basisfläche gemeinsam haben, gelten als Nachbarn. Sie ist nach Edward F. Moore benannt und wird auch als 8er-Nachbarschaft bezeichnet. Sie entspricht den Zugmöglichkeiten des Königs beim Schach"[3].

 
Die Moore-Nachbarschaft besteht aus 8 Zellen, welche die mittlere Zelle C umschließen.

Das bedeutet für unsere Moore-Matrix, dass alle Punkte die im inneren der Matrix liegen, jeweils   Nachbarn haben. Die Punkte, die auf den Rändern liegen, haben nur   Nachbarn. Die Punkte in den Ecken haben nur   Nachbarn. Somit sieht unser Moore-Matrix folgendermaßen aus:

 

Die dazugehörige Octave-Implikation sieht folgendermaßen aus:

  MM = ones(Y,X)*8; #Zuerst werden alle Einträge der Matrix auf 8 gesetzt              
  #Randpunkte haben 5 Nachbarn, daher werden alle diese auf 5 gesetzt.
  for i=1:X                      
  MM(1,i)=5;
  MM(Y,i)=5;
  endfor
  for j=1:Y                      
  MM(j,1)=5;
  MM(j,X)=5;
  endfor
  #Eckpunkte haben 3 Nachbarn, somit werden diese auf 3 festgelegt
  MM(1,1)=3;                     
  MM(1,X)=3;
  MM(Y,1)=3;
  MM(Y,X)=3;
Matrizen zum Zwischenspeichern Bearbeiten

Anschließend werden 3 Matrizen zum zwischenspeichern der Werte erstellt, welche bei Bewegung entstehen. Auch diese sind zu Anfang mit  -en gefüllt.

  ZS = zeros(Y,X);        #Zwischenspeicher Succeptible
  ZI = zeros(Y,X);        #Zwischenspeicher Infected
  ZR = zeros(Y,X);        #Zwischenspeicher Recovered


Funktionen zur Bewegung Bearbeiten

Am Anfang der Implementierung haben wir festgelegt, dass sich   der Menschen in den jeweiligen Matrizen bewegen. Nun haben wir je eine Funktion erstellt, die angibt, wie viele Menschen sich wohin bewegen, und wie viele Menschen bleiben.

Diese sehen folgendermaßen aus:

Bewegungsfunktion:

  function wert=anteil_Bewegung(l,k,j,i,q,t,MM,Z,SIR)
  wert=Z(l,k)+q/MM(j,i)*SIR(j,i,t-1);
  endfunction

keine_Bewegung-Funktion:

  function wert=anteil_keine_Bewegung(j,i,q,t,Z,SIR)
  wert=Z(j,i)+(1-q)*SIR(j,i,t-1);
  endfunction


Nun haben wir alle erforderlichen Schritte durchgeführt, um einen Transportprozess durchlaufen zu lassen.

Es werden nun für alle Werte, die innerhalb des Schachbrettes liegen, auf einen Teil die Bewegungs- auf den anderen die keine_Bewegung-Funktion angewandt. Dabei wird zuerst festgelegt, welcher Anteil bleibt und erst dann auf die nicht Bleibenden die Bewegungsfunktion angewandt. Die Funktionen laufen sowohl auf den Matrizen S, I und R. Die neu berechneten Werte werden dann in den Zwischenspeichermatrizen gespeichert.

  #Alle Zeitschritte werden durchlaufen
  for t=2:T;
  #ERSTENS: MENSCHENWANDERUNG
  #Pro Zeitschritt werden alle Felder durchlaufen
  for i=1:X
   for j=1:Y
    #Pro Feld geht der Anteil q in die MM
     for k=(i-1):(i+1)
       for l=(j-1):(j+1)
         #Liegt k oder l außerhalb des Definitionsbereiches, soll nichts getan werden
         if (((k==0 || k==X+1) || l==0) || l==Y+1) 
           a=0; #do nothing
                   
         #Der Anteil (1-q) bleibt in der Zelle selbst
         elseif (j==l && i==k)
           ZS(j,i)=anteil_keine_Bewegung(j,i,q,t,ZS,S);
           ZI(j,i)=anteil_keine_Bewegung(j,i,q,t,ZI,I);
           ZR(j,i)=anteil_keine_Bewegung(j,i,q,t,ZR,R);
        
                              
         #Auf alle anderen MM wird der Anteil q aufgeteilt
         else
           ZS(l,k)=anteil_Bewegung(l,k,j,i,q,t,MM,ZS,S);
           ZI(l,k)=anteil_Bewegung(l,k,j,i,q,t,MM,ZI,I);
           ZR(l,k)=anteil_Bewegung(l,k,j,i,q,t,MM,ZR,R);
         endif
       endfor
     endfor
   endfor
  endfor
Funktionen für S, I und R Bearbeiten

Nun haben wir neue Werte für die Anzahl der Menschen in den jeweiligen Matrizen für S, I und R erhalten. Diese sind noch in den Zwischenspeichermatrizen enthalten. Nun müssen wir auf die Werte noch die Funktionen für S, I und R anwenden um das SIR-Modell zu erhalten. Dafür werden folgende Funktionen benötigt:

Susceptible:

  function wert=S_funktion(j,i,t,gamma,S,ZS,ZI,ZR)
  wert = ZS(j,i)-(0.29*ZS(j,i)*ZI(j,i));
  endfunction


Infected:

  function wert=I_funktion(j,i,t,gamma,S,ZS,ZI,ZR)
  wert = ZI(j,i)+0.29*ZS(j,i)*ZI(j,i)-gamma*ZI(j,i);
  endfunction

Recovered:

  function wert=R_funktion(j,i,t,gamma,B,ZS,ZI,ZR)
  wert = ZR(j,i)+gamma*ZI(j,i);
  endfunction

Diese Funktionen werden nun auf die Zwischenspeichermatrizen angewandt. Die Ergebnisse davon werden dann in die Ursprungsmatrizen von S, I und R gespeichert und die Zwischenspeicher wieder auf   gesetzt.

  for i=1:X
   for j=1:Y
       S(j,i,t) = S_funktion(j,i,t,gamma,S,ZS,ZI,ZR);
       I(j,i,t) = I_funktion(j,i,t,gamma,S,ZS,ZI,ZR);
       R(j,i,t) = R_funktion(j,i,t,gamma,B,ZS,ZI,ZR);
    endfor 
   endfor
 
   #Zwischenspeichermatrix gleich Null setzen
   ZS = zeros(Y,X);
   ZI = zeros(Y,X);
   ZR = zeros(Y,X);
   endfor
SIR-Modell geplottet Bearbeiten

Nun konnten wir uns die Werte zu bestimmten Zeiten in unserem Gitter durch Plotten anzeigen lassen. Wir haben sie für jeden 5. Zeitschritt geplottet. Es folgt ein Beispiel der Implementierung anhand der kummulierten Infizierten. Die Implementierung der anderen Ausgaben ist ähnlich, nur dass   ersetzt werden muss.

  for i=1:T/5;
  t=5*i;
  figure(t)
  Z=(I(:,:,t)+R(:,:,t));
  surf((Z), "EdgeColor", "none")
  colormap ("jet")
  colorbar
  caxis ([0 max(max(max(I+R)))])
  axis([1 12 1 10 -0.1 max(max(max(I+R)))])
  title(["kummulierte Infizierte t=",num2str(t)])
  xlabel("x")
  ylabel("y")
  test=["Fig_", num2str(t),".jpg"]
  saveas(t, test)
  endfor

Kummulierte Infizierte:

  Infizierte:   Anfällige:

  Genesene:  

SIRV-Modell geplottet Bearbeiten

Das Gleiche haben wir mit unserem SIRV Modell versucht.

Dazu haben wir die Implementierungen für die SIR Funktionen geändert und die V-Funktion hinzugefügt:

S-Funktionen

  function wert=S_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZS(j,i)-(0.29*ZS(j,i)*ZI(j,i));
  endfunction
  function wert=S_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZS(j,i)+R(j,i,t-183)-(0.29*ZS(j,i)*ZI(j,i));
  endfunction
  function wert=S_funktion3(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZS(j,i)+R(j,i,t-183)-ZV(j,i)-(0.29*ZS(j,i)*ZI(j,i));
  endfunction


I-Funktion

  function wert=I_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZI(j,i)+0.29*ZS(j,i)*ZI(j,i)-gamma*ZI(j,i);
  endfunction

R-Funktionen

  function wert=R_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZR(j,i)+gamma*ZI(j,i);
  endfunction
  function wert=R_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZR(j,i)-R(j,i,t-183)+gamma*ZI(j,i);
  endfunction

V-Funktionen

  function wert=V_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZV(j,i);
  endfunction
  function wert=V_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZV(j,i)+141.89;
  endfunction
  function wert=V_funktion3(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV)
  wert = ZV(j,i)+0.027*(Bd(j,i)-ZV(j,i));
  endfunction

Ebenfalls mussten wir Matrizen für V und ZV erstellen, die am Anfang mit Nullen belegt wurden.

So sah dann unsere Modellierung aus:

  for i=1:X
   for j=1:Y
       S(j,i,t) = S_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
       I(j,i,t) = I_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
       R(j,i,t) = R_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
       V(j,i,t) = V_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
  
  if   t>183   && t<=339 && S(t)+R(t-183)<=B && R(t)-R(t-183)>=0
    S(j,i,t) = S_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
    I(j,i,t) = I_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
    R(j,i,t) = R_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
    V(j,i,t) = V_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
  endif

  if t >339 && t<=T && S(t)+R(t-183)<=B && R(t)-R(t-183)>=0
   S(j,i,t)=S_funktion3(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
   I(j,i,t) = I_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
   R(j,i,t) = R_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
   V(j,i,t) = V_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
  endif 
 
   if t>443 && t<=T && S(t)+R(t-183)<=B && R(t)-R(t-183)>=0;
   S(j,i,t) = S_funktion3(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
   I(j,i,t) = I_funktion(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
   R(j,i,t) = R_funktion2(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
   V(j,i,t) = V_funktion3(j,i,t,T,gamma,S,R,B,ZS,ZI,ZR,ZV);
   endif 
   endfor
   endfor

Kontinuierliche Diffusionsprozesse (Hundertmark) Bearbeiten

Wie am Anfang dieser Seite bereits erwähnt, wurden uns Aufgaben zur Bearbeitung gestellt. Dabei gab es 5 Übungsaufgaben, die hier chronologisch aufgezeigt werden. Die Abkürzung FDM, die in einigen Überschriften vorkommt bezeichnet hier die Finite-Differenzen-Methode. Die Übungsaufgaben sollen Versuche sein, durch Modelle realistische Aussagen über die Pandemie-Lage treffen zu können. Für alle Übungsaufgaben wurden uns von Frau Hundertmark Ansätze und Beispiel gezeigt, sodass wir bei einigen nicht mehr viel ändern mussten. Bei Aufgabe 4 und 5 haben wir uns größtenteils an Gruppe 1 orientiert. [4]

1. Übungsaufgabe SW1: Kontaktmodell Bearbeiten

Die Arbeitsaufträge der ersten Übungsaufgabe waren:

  • einfaches Kontaktmodell erstellen
  • Simulation für verschiedene Ansteckungsradien
  • unterschiedliche Position des Infizierten
  • verschiedene Bewegungsgeschwindigkeiten
  • verschiedene Bewegungsrichtungen


Einfaches Kontaktmodell Bearbeiten

Was ist ein Kontaktmodell? Ein Kontaktmodell ist ein Modell, bei dem sich Punkte bewegen, die sich unter einer gewissen Abstandsschranke mit einem rotem Punkt ebenfalls rot einfärben. Die Punkte sollen selbstverständlich Menschen darstellen. Die roten Punkte sind infizierte Menschen, die andere ebenfalls unter einem gewissen Abstand infizieren.

Schachbrett und Anfangswerte Bearbeiten

Zuerst erstellen wir eine 20x20 Matrix bzw. ein Schachbrett mit den längen 20x20 und legen unsere Anfangswerte fest:

  Nx=20;             %Anzahl von Punkten in x und y Richtung
  Ny=20;
  Zeitschritte=3;    %pro eine Zeiteinheit T=1, pro Zeiteinheit 3 Schritte
  radiusInf=0.50;    %Radius für die Verbreitung der Infektion bei Kontakt (Ansteckungsradius)
  T=3;               %Die Berechnung wird für 3 Zeiteinheiten laufen
  g=0.50;            %Geschwindigkeit mit der sich die Fußgänger bewegen
  x=[1:Nx];          % Vektoren der x und y Koordinaten
  y=[1:Ny];
  dt=1/Zeitschritte;
  [x,y]=meshgrid (x,y);      % Erstellung des Schachbrettes. Ein Punkt steht für eine Person
Position Infizierte Person Bearbeiten

Anschließend setzen wir den ersten Infizierten in die Mitte des Schachbrettes und lassen uns dies Graphisch ausgeben:

  xInf=x(1, Nx/2);
  yInf=y(Ny/2);
  IndInf2=Nx/2;
  IndInf1=Ny/2;
  IndInf1neu=IndInf1;
  IndInf2neu=IndInf2;
  close all;
  figure (1)
  hold on;
  plot(x,y, '*b') ;
  plot(xInf,yInf, 'sr') ;
  axis([-5 25 -5 25]);
  hold off;
 
Schachbrett mit einem Infizierten in der Mitte
Bewegungsgenerierung Bearbeiten

Danach werden zufällige Bewegungen generiert. Dafür wird zuerst durch eine Bewegungsgleichung die Zielposition der Punkte bestimmt.

  neuPosX=x.+g.*rand(Ny,Nx)-0.5*g;  %Neue zufällige Zielposition der sich bewegenden Punkte (Personen)
  neuPosY=y.+g.*rand(Ny,Nx)-0.5*g;

Anschließend werden die neuen Positionen für jeden Zeitschritt berechnet, mit den Infiziertenpositionen abgeglichen und ausgegeben:

  %Zeitschleife für 3 Zeitschritte pro eine Zeiteinheit T, zur Überprüfung ob neue Infizierte pro 
  Zeitschritt dazukommen
  for i=1:T*Zeitschritte
  neuX=x.+1*(neuPosX.-x)*i*dt;
  neuY=y.+1*(neuPosY.-y)*i*dt;
  figure (i+20)
  title(['t=' num2str(i*dt)])
  axis ([-5 25 -5 25]);
  hold on;
  plot(neuX,neuY,'*b');
  for k1=1:length(IndInf1)
  for j=1:Nx
  for l=1:Ny
  %die aktuellen Positionen der Fußgänger-Punkte werden mit den Positionen der Infizierten abgeglichen 
  (Abstand wird berechnet)
     abstand=norm ( [neuX(l,j)-neuX(IndInf1(k1),IndInf2(k1)), neuY(l,j)-neuY(IndInf1(k1),IndInf2(k1))]);
       if abstand<radiusInf
        %wenn der Abstand zum Infizierten unter dem Ansteckunsradius liegt, wird  der l,j-te  Punkt 
        infiziert (mit rotem Quadrat gekenzeichnet)
        abstand;    
           plot(neuX(l,j),neuY(l,j), 'sr'); 
           k2=1;
           % der Vektor der Infizierten wird untersucht, falls die l,j-Indizes der aktuellen Punkte nicht unter den infizierten Indizes auftauchen, werden  die l,j-Indizes des aktuell Infizierten zu den neuen Vektoren der Infizierten-Indizes
           % IndInf1neu, IndInf2neu zugefügt.(Grund: Speicheroptimierung)
           while k2 <=length(IndInf1)&&(l!=IndInf1neu(k2) || j!=IndInf2neu(k2)) 
            k2=k2+1;
           endwhile
           if k2 >length(IndInf1)
             IndInf1neu=[IndInf1neu l];
             IndInf2neu=[IndInf2neu j];
           endif
       endif
    endfor
  endfor
  endfor
  IndInf1=IndInf1neu;
  IndInf2=IndInf2neu;
  hold off
  lengt=length(IndInf1);
  endfor
  %Zeitschleife abgeschlossen

Wir erhalten folgende grafisches Ausgabe:

 

Da wir den Abstand, ab dem sich Menschen infizieren ziemlich klein gewählt haben und auch die Geschwindigkeit der Individuen relativ gering war, hat sich in 3 Zeiteinheiten nur eine weitere Person angesteckt. Im Folgenden werden wir noch sehen, was eine Geschwindigkeitsänderung ausmachen kann.

Versechsfachung der Geschwindigkeit Bearbeiten

Versechsfachen wir die Geschwindigkeit der Individuen wie folgt, stecken sich wesentlich mehr Personen an, als vorher.

Die Zeitschleife bleibt fast unverändert. Lediglich die Berechnung der neuen Positionen verändert sich zu:

  neuX=x.+Param*(neuPosX.-x)*i*dt;
  neuY=y.+Param*(neuPosY.-y)*i*dt;

 

Bei einer langsameren Geschwindigkeit würde sich niemand neues anstecken, weswegen wir diesen Plot auslassen.

Änderung Infiziertenradius Bearbeiten

Da kaum neue Infektionen entstanden sind, haben wir das gleiche nochmal mit einem größeren Ansteckungsradius von 0.9 durchgeführt. Einmal mit normaler Geschwindigkeit und einmal Versechsfacht.

  radiusInf=0.9;

Ursprungsgeschwindigkeit:

 

Hier sieht man eine riesen Veränderung zu vorher. Ein größerer Ansteckungsradius lässt viel mehr Infizierte entstehen.

Versechsfacht:

 

Auch hier sind viel mehr neue Infizierte entstanden.

In den weiteren Beispielen arbeiten wir wieder mit dem kleineren Infektionsradius.

Änderung Anfangsposition Bearbeiten
Rand Bearbeiten

Wir wollen nun schauen was passiert, wenn die Infizierte Person nicht in der Mitte des Gitters, sondern am Rand des Gitters ist. Dafür ändern wir im Skript die Befehle für die Infiziertenposition wie folgt ab:

  %erste Infizierte 
  xInf=x(1, Nx/2);
  yInf=y(1);
  IndInf2=Nx/2;
  IndInf1=1;
  IndInf1neu=IndInf1;
  IndInf2neu=IndInf2;

Lässt man dieses Modell genauso durchlaufen wie das erste, erhalten wir folgende graphische Ausgabe:

 

Auch hier infizieren sich nur wenige.

Was passiert dieses Mal bei einer Versechsfachung der Geschwindigkeit?

 

Auch hier sieht man, dass eine schnellere Bewegung, zu mehr Infektionen führt, allerdings sind es weniger Infektionen wie bei dem Infizierten in der Mitte.

Ecke Bearbeiten
   %erste Infizierte 
   xInf=x(1, 1);
   yInf=y(1);
   IndInf2=1;
   IndInf1=1;
   IndInf1neu=IndInf1;
   IndInf2neu=IndInf2;

 

Versechsfachung:

 

Änderung Bewegungsrichtung Bearbeiten

Wir ändern nun die Richtung der Bewegung in jedem Zeitschritt. Durchgeführt wird dies, mit der Abstandsschranke von 0.9, da sich bei kleinerem Ansteckungsradius niemand angesteckt hatte.


  for i=1:T*Zeitschritte
  neuX=x.+1*(neuPosX.-x)*1*dt;
  neuY=y.+1*(neuPosY.-y)*1*dt;
  x=neuX;
  y=neuY;
  neuPosX=neuX.+g.*rand(Ny,Nx)-0.5*g;
  neuPosY=neuY.+g.*rand(Ny,Nx)-0.5*g;
  figure (i+20)
  title(['t=' num2str(i*dt)])
  plot(neuX,neuY, '*b') ;
  hold on;
  axis([-5 25 -5 25]);
  quiver(neuX,neuY,neuPosX.-x,neuPosY.-y,'m')
  title(['t=' num2str(i*dt)])
  for k1=1:length(IndInf1)
  for j=1:Nx
   for l=1:Ny
     abstand=norm ( [neuX(l,j)-neuX(IndInf1(k1),IndInf2(k1)), neuY(l,j)-neuY(IndInf1(k1),IndInf2(k1))]);
       if abstand<radiusInf
            abstand;    
           plot(neuX(l,j),neuY(l,j), 'sr') ;
           %---------------------------
           k2=1;
           % der Vektor der Infizierten wird untersucht, falls die l,j-Indexen des aktuellen Punkten nicht unter den
           %infizierten Indexen auftauchen, werden  die l,j-Indexen des aktuell Infizierten zu den neuen Vektoren der Infizierten-Indexen
           % IndInf1neu, IndInf2neu zugefügt.
           %(Grund: Speicheroptimierung)
           while k2 <=length(IndInf1)&&(l!=IndInf1neu(k2) || j!=IndInf2neu(k2)) 
            k2=k2+1;
           endwhile
           if k2 >length(IndInf1)
             IndInf1neu=[IndInf1neu l];
             IndInf2neu=[IndInf2neu j];
           endif
       endif
    endfor
  endfor
  endfor
  IndInf1=IndInf1neu;
  IndInf2=IndInf2neu;
  hold off
  lengt=length(IndInf1);
  endfor


 

2. Übungsaufgabe SW2: Fundamentallösungen Bearbeiten

Bei der zweiten Aufgabe sollten wir Diffusionsgleichungen durch Fundamentallösungen lösen. Sowohl für stationäre als auch für instationäre Fälle mit inhomogenen Differentialgleichungen.

Stationärer Fall Bearbeiten

Zuerst betrachten wie den stationären Fall. Hierfür legen wir zuerst ein quadratisches Gebiet in   fest, über welches die Implementierung laufen soll. Die Schrittweite des Gitters legen wir auf 0,03 fest.

  step=0.03
  X=[0:step:2]; 
  Y=[0:step:2];
  [x,y]=meshgrid(X,Y);


Des weiteren soll nun eine Infektionsquelle auf dem Gebiet festgelegt werden. Diese haben wir definiert mit:

  function wert=Quellfunktion(x,y)
  if sqrt((x.-2).^2+(y.-2).^2)<=0.15 wert=1
  else wert=0
  if sqrt ((x.-2).^2+(y.-0).^2)<=0.15 wert=1
  else wert=0
  if sqrt((x.-0).^2+(y.-2).^2)<=0.15 wert=1
  else wert=0
  if sqrt ((x.-0).^2+(y.-0).^2)<=0.15 wert=1
  else wert=0;
  endif
  endif
  endif
  endif
  endfunction

Um die Funktionswerte der Funktion   in jedem Gitterpunkt   der Matrix speichern zu können benötigen wir folgende Implementierung:

  for i=1:(length(X))
  for j=1:(length(Y))
  f(j,i)=Quellfunktionneu(x(j,i),y(j,i));
  endfor
  endfor
 

Unsere Infektionsquelle auf dem Gebiet sieht somit folgendermaßen aus:

 

Die Lösung der inhomogenen Laplace-Gleichug, der Poissongleichung   auf   lässt sich mithilfe der Faltung der Fundamentallösung und der Funktion der rechten Seite berechnen.

Fundamentallösung:  ,

wobei die Formel der Fundamentallösung für   für   ist:

 

  = Volumen der Einheitskugel in  ,   = Vektornorm in  
Für n=3 ist  .

Dabei ist die Faltung von   und   die doppelte Integration von   und  

Da wir unser Gebiet auf   definiert haben, nutzen wir die obere Gleichung für  .

Das doppelte Integral kann dann mit der Trapezregel berechnet werden.

Octave-Code:

  for i=1:(length(X)) 
  for j=1:(length(Y))
  xstar=x(j,i)*ones(length(Y),length(X));
  ystar=y(j,i)*ones(length(Y),length(X));
  phi=-log(sqrt((xstar.-X).^2+(ystar.-Y).^2))/(2*pi);
  phi(j,i)=0;
  I(j,i) = trapz(Y,trapz(X,phi.*f,2));
  endfor  
  endfor

Als Lösung der Poissongleichung erhalten wir nun:

 

Bei der Quellfunktion erhielten wir eine Funktion mit 4 Trägern. Diese könnten in der Corona-Pandemie Hotspots darstellen. Bei der Lösung der Poissongleichung kann man erkennen, wie sich die Infektion von den Hotspots auf verteilt bis das ganze Gebiet Infiziert ist. Dabei sind zu den Ecken hin. mehr Infizierte als in der Mitte des Gebietes, da in den Ecken die Quellen waren.

Instationärer Fall Bearbeiten

Die homogene Differentialgleichung   mit dem konstanten Diffusionskoeffizienten   wird mit folgender Fundamentallösung gelöst:  

mit  

  = Quadrat der Euklidischen Norm von  .

1. Anfangslösung Bearbeiten

Den Instationären Fall haben wir mehrmals durchgeführt. Einmal mit der Quellfunktion als Anfangslösung aus dem stationären Fall (mit verschiedenen Konstanten für   ) und einmal mit einer anderen Anfangslösung.

Lassen wir oben genannte Quellfunktion als Anfangslösung u_0 über 3 Zeitschritte laufen mit folgenden Befehlen:

Lassen wir die Funktion über 3 Zeiteinheiten mit je 3 Zeitschritten laufen:

  T=3
  Zeitschritte=3
  dt=1/Zeitschritte;
  t0=0.001;
  a=10
  for k=0:T*Zeitschritte
   t=t0+k*dt
   for i=1:(length(X))
   for j=1:(length(Y))
   xstar=x(j,i)*ones(length(Y),length(X));
   ystar=y(j,i)*ones(length(Y),length(X));
   psi=(1/(4*pi*a*t))*exp(-((xstar.-x).^2+(ystar.-y).^2))/(4*a*t);
   #Faltung von Anfangslosung und psi
   J(j,i) = trapz(Y,trapz(X,psi.*u0,2));
   endfor
   endfor
   Losung(:,:,k+1)=J; #Damit nach der Zeitschleife auf verschiedene Lösungen
   #zugegriffen werden kann, werden sie hier gespeichert
   endfor

Die Lösung nach den jeweiligen Zeitschritten wird durch folgende Implementierung graphisch ausgegeben:

  for k=0:T*Zeitschritte
  figure(3+k+1)
  meshc(x,y,Losung(:,:,k+1))
  grid on
  title(['Loesung der Differentialgleichung in t=',num2str(t0+k*dt)])
  xlabel('x')
  ylabel('y')
  test=["Fig_", num2str(k+1),".jpg"]
  saveas(k+1, test)
  endfor

Wir erhalten folgende grafische Darstellungen:

Im abgebildeten Octave Plot wählten wir den Diffusionskoeffizienten  :  

Ändert man diese auf   erhalten wir:  

 :

 

 :

 

Hieran kann man erkennen, dass je größer kleiner der Diffusionkoeffizient   ist, desto größer werden die Werte der Lösung der Differentialgleichung.

2. Anfangslösung Bearbeiten

Nun nutzen wir anstatt der Quellfunktion die Anfangslösung, also eine Funktion, die zum Zeitpunkt   in das Gebiet eintritt. Diese sieht folgendermaßen aus:

  function wert=Anfangslosung(x,y)
  if sqrt((x.-0.2).^2+(y.-0.4).^2)<=0.05 wert=1;
  else  if sqrt((x.-1.2).^2+(y.-1.4).^2)<=0.04 wert =0.5;
  else  wert=0;
  endif
  endif
  endfunction

Um die Funktionswerte der Funktion   in jedem Gitterpunkt   der Matrix speichern zu können benötigen wir folgende Implementierung:

  for i=1:(length(X))
  for j=1:(length(Y))
  u0(j,i)=1*Anfangslosung(x(j,i),y(j,i));
  endfor
  endfor

Wir erhalten:

 

und die dazugehörige lösung der Differentialgleichung

 

Hier sieht man, dass die Verteilung der Lösung Zeitabhängig ist. Desto länger die Lösung im System ist, desto mehr verteilt sie sich. Da die Lösung aber relativ wenig für das große Gebiet war, wird die Funktion am Ende so flach, dass sie kaum noch zu sehen ist.

3. Übungsaufgabe SW4: Kompartimentmodelle Bearbeiten

Aufgaben waren dieses Mal Kompartimentmodelle für Deutschland zu erstellen:

  • Erstellen SI-Modell
    • verschiedene Infektionsraten
  • Erstellen SIR-Modell
    • Vergleich zu den realen Daten des RKI -exponentielles Wachstum
  • Modifiziertes SIR-Modell
    • Faktor r
    • Slowdownfunktionen einbauen

SI-Modell Bearbeiten

Zuerst legen wir die Anfangswerte fest. Es sollte angenommen werden, dass sich nur 2 Drittel der deutschen Bevölkerung infizieren kann. Das entspricht 55 Millionen Menschen.

  B = 55000;              %Kapazität in Tausend
  beta=0.29;              %Infektionsrate 
  gamma= 1/14;            %Genesungsrate
  times=(0:0.1:180);      %Zeitspanne
  I0=16/1000;             %Anzahl Infizierte, zum Zeitpunkt t0
  y0=[B-I0;I0;];          %Anfangswerte Spaltenvektor

Dann implementieren wir die Funktion der rechten Seite mit der Octave arbeiten soll. Schaut man sich die Funktionen in der eckigen Klammer bei   an, erkennt man die Gleichungen des SI-Modells wobei  ,   und   sind:

 
 
  %Funktion der rechten Seite einbauen
  %Definiere die Funktion f der rechten Seite des DGL Systems y'=f(y,t), Vektorwertige Funktion f
  f=@(y,x)[-beta*y(1)*y(2)/B;beta*y(1)*y(2)/B];

Dies soll nun für jeden Zeitschritt ausgerechnet und geplottet werden:

  %numerische Lösung 
  y=lsode(f,y0,times);
  figure 1
  plot (times, y (:,1),'.',times, y (:,2), '.');
  legend("Succeptible","Infected","location","east")
  title ('SI Modell')

Wir erhalten:

 

verschiedene Infektionsraten Bearbeiten

Wir haben nun verschiedene Infektionsraten gewählt und plotten lassen:

  %Betrachtung verschiedene Infektionsraten:
  beta0=0; 
  beta1=0.25;
  beta2=0.5;
  beta3=0.75;
  beta4=1;
  %Vektorwertige Funktionen für vers. Infektionsraten
  t=@(y,x)[-beta0*y(1)*y(2)/B;beta0*y(1)*y(2)/B];
  g=@(y,x)[-beta1*y(1)*y(2)/B;beta1*y(1)*y(2)/B];
  h=@(y,x)[-beta2*y(1)*y(2)/B;beta2*y(1)*y(2)/B];
  m=@(y,x)[-beta3*y(1)*y(2)/B;beta3*y(1)*y(2)/B];
  n=@(y,x)[-beta4*y(1)*y(2)/B;beta4*y(1)*y(2)/B];
  

Zur besseren Anschauung haben wir die ausgegebenen Bilder als Animation dargestellt und auch der beta-Wert des ersten Modells eingebaut:

 

Man sieht, je größer beta, desto schneller breitet sich die Infektion aus. Je kleiner beta, desto länger dauert die Infektion. Allerdings sind Werte von    eher unrealistisch.

SIR-Modell Bearbeiten

Die Anfangswerte vom SIR-Modell entsprechen denen des SI-Modells. Lediglich die Anfangswerte des Spaltenvektors und die Funktion der rechten Seite ändern sich. Zusätzlich kommt noch der Anfangswert der Genesenen hinzu.

Auch hier entspricht die Funktion der rechten Seite denen des SIR-Modells wobei  ,  ,   und  :

 

 

 

  R0=0;
  y0=[B-I0; I0; R0];
  %Funktion der rechten Seite 
  %Definiere die Funktion f der rechten Seite des DGL Systems y'=f(y,t), Vektorwertige Funktion f
  f=@(y,x)[-beta*y(1)*y(2)/B;beta*y(1)*y(2)/B-gamma*y(2);gamma*y(2)];
  %numerische Lösung 
  y=lsode(f,y0,times);
  plot (times, y (:,1),'.',times, y (:,2), '.', times, y (:,3),'.',times, y (:,3)+y (:,2),'.')
  legend("Succeptible","Infected","Removed","cummulative Infected","location","east")
  title ('SIR Modell, beta=0.29')

Dazugehörige Graphik:  

Änderung Infektionsraten Bearbeiten

Auch hier haben wir die Infektionsraten geändert und ein GIF erstellt. Die Infektionsraten entsprechen den gleichen wie denen des SI-Modells:


 

Modifiziertes SIR-Modell Bearbeiten

Bei dem modifizierten SIR-Modell sollten wir die tatsächlichen Werte für Genesene, Infizierte, Tode und Geheilte des RKI betrachten.

 
DatenRKI

Bisher haben wir für unsere SI und SIR-Modelle die Ableitungen von S, I und R genutzt. Möchte man die Gesamtanzahl der Infizierten berechnen benötigt man die I-Funktion. Welche wie folgt lautet:

 

Nutzen wir die I-Funktion mit unserem beta=0.29 anstelle von k, plotten diese für die ersten 30 Tage (da sie nur da einer Exponentialfunktion ähnelt und vergleichen dies mit den Daten des RKI erhalten wir folgendes:

 

Man sieht, dass die Daten des RKI mit den ersten 20 Tagen der Exponentialfunktion übereinstimmen, danach aber auseinander gehen.

Bestimmung Beta Bearbeiten

Wir suchen nun ein beta, für das die Daten sich noch mehr gleichen. Dafür bestimmen wir ein Residuum: "Als Residuum bezeichnet man in der numerischen Mathematik die Abweichung vom gewünschten Ergebnis, welche entsteht, wenn in eine Gleichung Näherungslösungen eingesetzt werden."[5]


Wir berechnen nun zuerst das Residuum von unserer Funktion mit beta=0.29 zu den Daten des RKI's:

  %Bestimmung des Residuums (Abweichung der exakten Lösung)
  for i=1:30       %Berechnung für jeden der 30 tage
  Infizierte=A(1,i);
  I(i)=I_0*exp(beta*(i-t_0));
  R(i)=(Infizierte.-I(i)).^2;
  endfor
  j=[1:30];
  R(j)
  Summe=(sum(R(j)));    %Gesamtabweichung aller Tage

Summe=97157

Anschließend haben wir uns von Cocalc ermitteln lassen, bei welchem Wert das Residuum den kleinsten Wert hat, bei welchem   also der kleinste Fehler für die ersten 30 Tage entsteht. Dafür wird die Residuenquadratsumme gebildet: "Bildet man die Summe der quadrierten Residuen für alle Beobachtungen, so erhält man die Residuenquadratsumme:

 


Diese spezielle Abweichungsquadratsumme taucht in vielen statistischen Maßen, wie z. B. dem Bestimmtheitsmaß, der F-Statistik und diversen Standardfehlern, wie dem Standardfehler der Regression auf. Die Minimierung der Residuenquadratsumme führt zum Kleinste-Quadrate-Schätzer."[6]:

  Summe=0; %Die Summe aller Residuen (also aller Abweichungen) muss 0 ergeben
  for beta=[0.2:0.002:0.4]
  for i=1:30
  Infizierte=A(1,i);
  I(i)=I_0*exp(beta*(i-t_0));
  R(i)=sum((Infizierte.-I(i)).^2);
  endfor
  j=[1:30];
  R(j);
  Summe=[Summe , (sum(R(j)))];
  endfor
  Summe/1000;

Ermittlung beta:

  MIN=min (Summe(2:length(Summe)))
  index=find(Summe==MIN)
  beta=[0.2:0.002:0.4];
  plot (beta,Summe(2:length(Summe)), '*')
  title ('Residuum')
  optim_Infrate=beta(index)

Dabei erhielten wir folgende Werte:

  MIN =  6839.1
  index =  28
  optim_Infrate =  0.25400

Diese bedeuten, dass das kleinste Residuum 6839.1 ist, wenn  

 
Residuum-Ausgabe

Vergleichen wir nun das SIR-Modell mit   mit den Daten des RKI durch nachstehende Implementierung erhalten wir folgende Abbildung:

  B=55000;        % Kapazitätsgrenze, 2/3 der deutschen Bevölkerung
  beta=0.254;     % Basisinfektionsrate- die Rate des exponentiellen Wachstums 
  gamma=1/14;     % Wechselrate zu den Genesenen
  d=0.003;        % Todesrate
  r=1;            % Anteil der erfassten Infizierten
  I0=16/1000;     % Anzahl der Infizierten in T0
  R0=0;           % Anzahl der Genesenen in T0
  times=(0:0.1:30);
  plot (times, y (:,2), 'r.', times, y (:,3),'b.',times, y (:,3)+y (:,2),'k .')
  plot (timesWHO, inf_falleWHO./1000, 'k *', timesWHO,inf_falleWHOaktuell/1000, 'r*' , 
  timesWHO,inf_falleWHOrecovered/1000, 'b*' )
  legend ("Infected", "Removed", "cummulative Infected " ,"German data I +R" ,"German data I ","German 
  data R" ,"location", "west")
  hold off

 


Man kann sehen, dass die Graphen nicht übereinstimmen. Das liegt daran, dass wir durch das Residuum eine Infektionsrate bestimmt haben, die am wenigsten von den Daten des RKI abweicht, nicht aber eine die gar nicht abweicht. Des Weiteren ist zu erkennen, dass die Kurven erst ab Tag 10 auseinandergehen und die Infektionsrate des RKI anscheinend höher ist als unsere. Die Kurven für R und I+R haben wir weggelassen, da die laut den Daten es in den ersten 30 Tagen noch keine Genesenen gab, somit   und   ist.

Einflussfaktor r Bearbeiten

Oben in der Implementierung ist dem ein oder anderen eventuell schon das   aufgefallen, welches in vorherigen Implementierungen nicht zu sehen war. R ist der Einflussfaktor der gemeldeten Daten. Ist   sind alle Infizierten auch beim RKI gemeldet. Ist   <  , so wurden nicht alle Infizierten erfasst.

Wir wollen nun die Auswirkungen von r auf das SIR Modell betrachten:

Gewählt haben wir 5 Werte für r:

   r=1
   r1=0.75;
   r2=0.5;
   r3=0.25;
   r4=0.1;
    % Funktion der rechten Seite angepasst:  
   f=@(y,x) [-beta*y(1)*y(2)/(r*B);beta*y(1)*y(2)/B-gamma*y(2);gamma*y(2)-d*y(2)];
   y = lsode (f, yo, times);

Wir erhalten folgende Bilder:

 

Slowdownfunktion Bearbeiten

Als nächstes wollen wir eine Slowdownfunktion erstellen die sowohl zu den Daten des RKI passt als auch die Maßnahmen und Lockerungen seit Beginn der Pandemie darstellen.

  function val=slowdown(x,t)
  % Ab Tag t (Argument der Funktion: 25) wir die Infektionsrate in mehreren Schritten sinken und steigen:
  if x<t val=1 ; 
            else if x<t +8 val=t./(x.^1.1);     %Schulschließung
            else if x<t +16 val=t./(x.^1.2);    %Kontaktbeschränkung
            else if x<t +51 val=t./(x.^1.3);    %Langzeitauswirkungen
            else if x<t +56 val=t./(x.^1.2);    %Lockerungen
            else if x<t +63 val=t./(x.^1.1);    %Demo Querdenker1
            else if x<t +88 val=t./(x.^1);      %Demo Querdenker2
            else if x<t +140 val=t./(x.^0.9);   %Urlaubssaison
            else if x<t +221 val=t./(x.^0.8);   %zweite Welle
            else if x<t +235 val=t./(x.^0.9);   %Verschärfung der Maßnahmen
            else if x<t +281 val=t./(x.^1);     %Lockdown light
            else if x<t +292 val=t./(x.^1.1);   %Schulschließung
            else if x<t +295 val=t./(x.^1);     %Weihnachten
            else if x<t +318 val=t./(x.^1.01);  %Impfungen (nur sehr wenig Auswirkungen)
            else if x<t +328 val=t./(x.^1.11);  %FFP2-Maskenpflicht
            else if x<t +366 val=t./(x.^1.12);  %zweiter Impfstoff
            else if x<t +373 val=t./(x.^0.92);  %Schulöffnungen + mehr Testungen
            else if x<t +377 val=t./(x.^0.91);  %Aussetzung Astra Zeneca
            else if x<t +390 val=t./(x.^0.92);  %Astra wieder aktiv
            else if x<t +393 val=t./(x.^0.93);  %Impfung Hausarzt
            else val=t./(x.^0.83) ;             %Ostern / schönes Wetter Menschen gehen mehr raus
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
  endif
  if x> 418 val=0.2; endif
  endfunction


Wir haben die Funktion mit den Daten des RKI abgeglichen und auch hier eine geeignete Infektionsrate durch die Residuenquadratsumme bestimmt, denn die zuvor bestimmte, passte nicht mehr so sehr zu der Slowdownfunktion. Für  ergab sich nun der Wert  .

 
Residuum Slowdown

Geplottet auf die ersten 100 Tage und verglichen mit den Daten des RKI kann man erkennen, dass die tatsächlichen Werte sich den jeweiligen Funktionen sehr ähneln.

 

Implementiert man die Slowdownfunktion komplett, erhält man folgende Graphik:

 


Man sieht, dass diese das Infektionsgeschehen zwar verlängert, aber dennoch nicht die Realtität abbildet, denn sonst hätten wir die Pandemie schon Ende letzten Jahres überstanden.

4. Übungsaufgabe SW7: Randwertaufgabe für Poissongleichung mit FDM Bearbeiten

In dieser Aufgabe sollten wir die stationäre Diffusion mithilfe der Poisson-Gleichung auf einem rechteckigem Gebiet mit der Finiten-Differenzen Methode implementieren. Die Methode ist ein Gitter-basiertes Verfahren, welches die unbekannte Funktion   auf endlich vielen Gitterpunkten   approximiert.

 

 

Zunächst müssen einige Eigenschaften wie die Quelldichtefunktion, das Gebiet etc. festgelegt werden:

Die "rechte Seite" der Poisson-Gleichung Bearbeiten

Die "rechte Seite" der Poissongleichung besteht aus einer Quelldichtefunktion  welche die Flussgeschwindigkeit der Quelle in das System hinein beschreibt. Bezogen auf die Corona-Pandemie, also die Geschwindigkeit in der Neuinfizierungen kontinuierlich in das System/in einem Gebiet hinzukommen.

  function wert=Quellfunktion(x,y)
   if sqrt((x.-3.0).^2+(y.-4).^2)<=0.25 wert=1; 
    else wert=0;
   endif
  endfunction

Gebiet der Modellierung Bearbeiten

Um ein Gebiet D festzulegen, müssen die Kantenlängen des Rechtecks angegeben werden. Des Weiteren benötigt man die Anzahl an Gitterunkten in X-Richtung:

  xend=9
  yend=6
  N=30  %Anzahl von X-Punkten (ohne Randpunkte)

Um das äquidistante Gitter erstellen zu können, muss der Abstand zwischen den einzelnen Gitterpunkten festgelegt werden. Dafür muss die  -Kantenlänge durch   geteilt werden, da der  -te und  -te Index den Rändern entspricht und nicht zu den Gitterpunkten zählen:

  hx=xend/(N+1)
  hy=hx;
  M=floor((yend/hy))-1
  [x,y]=meshgrid(hx:hx:xend-hx,hy:hy:yend-hy);

Zusätzlich benötigen wir noch einen konstanten Diffusionskoeffizienten (Verbreitungsgeschwindigkeit). Je größer dieser ist, desto schneller erfolgt die Verbreitung.

  a=1.5

Randbedingungen Bearbeiten

Dirichlet-Randwertproblem Bearbeiten

Bei dem Dirichlet Randwertproblem ist die gesuchte Funktion   am Rand   durch eine Funktion   gegeben.

 
 

Wir wählen für unsere Funktion   für die verschiedenen Ränder einen konstanten Wert:

  %Dirichlet-RB:
  wert_unten=-0.035
  wert_oben=0.035
  wert_links=0.035
  wert_rechts=-0.035

Systemmatrix

Um die gesuchte Funktion   zu berechnen, muss   approximiert werden. Eindimensional kann dabei   betrachtet werden. Die zweite Ableitung kann dabei mit Hilfe des zentralen Differenzenquotienten diskretisiert werden:

  für jedes  .

Hier bezeichnet  .

Dieser ergibt sich aus der Differenz des Rückwärts- und des Vorwärtsdifferentenquotienten  .

Bei einer zweidimensionalen Betrachtung wie bei unserem Fall (rechteckiges Gebiet   ), müssen zwei Raumrichtungen x und y berücksichtigt werden und damit zwei Differenzenquotienten   aufgestellt werden.

Diese werden durch die partiellen Ableitungen im Punkt   approximiert:

 ,
 

Summiert man diese erhält man:

 

Um die Systemmatrix aufzustellen zu können, müssen die unbekannten Funktionswerte   aller Gitterpunkte, sowie die Funktionswerte der rechten Seite   in je einen langen Vektor eingeordnet werden. Diese sollen wie folgt aufgestellt werden:

 
 

Daraus lässt sich ein lineares Gleichungssystem   aufstellen, bei welchem   die blockdiagonale Matrix ist.

Es folgt:

  mit Diagonalblock  

und der Einheitsmatrix   auf der Nebendiagonale.

Praxis

Um die oben genannte Theorie zu implementieren wird zuerst die Systemmatrix folgendermaßen aufgestellt:

  Vec1=ones(N*M,1)  %erzeug Vektor der Länge N*M
  BB=diag(-4.*Vec1,0)+diag(ones(N*M-1,1),1)+diag(ones(N*M-1,1)-1)+diag(ones(N*(M-1),1),N)+diag(ones(N*(M-1),1),-N); 
  %Systemmatrix N^2xM^2 mit -4 auf der Diagonale, 1 auf den Nebendiagonalen und 1 auf den N und -N-ter Nebendiagonalen

Es muss zusätzlich beachtet werden, dass beim Übergang in die nächste Blockmatrix B die Nebendiagonalen aus Einsen unterbrochen werden und dort je ein Nulleintrag vorliegt:

 

Diese Eigenschaft wird durch folgenden Befehl implementiert:

  %Korrektur der Matrix (Blockdiagonalität)
  for i=1:(M-1)
  BB(i*N+1,i*N)=0;BB(i*N,i*N+1)=0;
  endfor


Anschließend wird die Matrix mit dem Diffusionskoeffizient/h² multipliziert:

  BB=BB*a/hx^2

Matrixdarstellung: (s.Bild: Sytemmatrix)

 
Systemmatrix
  figure(1);
  spy(BB);
  xlabel("Spalten")
  ylabel("Zeilen")
  zlabel("Matrix B")
  title ("Systemmatrix B");

Rechte Seite der Poissongleichung

Um die rechte Seite des Systems aufzustellen, wird die oben definierte Quellfunktion für jeden Gitterpunkt gespeichert. Danach werden die Dirichlet-Randbedingungen hinzugefügt.

  clear f;
  for i=1:N
  for j=1:M
  f(j,i)=1*Quellfunktion(x(j,i),y(j,i));  %*hx^2;
  %Dirichlet Randbedingung unten und oben:
  if j==1 f(j,i)=1*Quellfunktion(x(j,i),y(j,i))+wert_unten*a/hx^2; endif #(wegen Poisson muss NRB 
  1/h^2)
  if j==M f(j,i)=1*Quellfunktion(x(j,i),y(j,i))+wert_oben*a/hx^2; endif
  %Dirichlet Randbedingung links und rechts:
  if i==1 f(j,i)=1*Quellfunktion(x(j,i),y(j,i))+ wert_links*a/hx^2; endif
  if i==N f(j,i)=1*Quellfunktion(x(j,i),y(j,i))+ wert_rechts*a/hx^2; endif
  endfor
  endfor
  

Ecken

Die Ecken müssen anders betrachtet werden, da hier zwei Randbedingungen aufeinandertreffen:

  f(1,1)=1*Quellfunktion(x(j,i),y(j,i))+(wert_links+wert_unten)*a/hx^2; 
  f(1,N)=1*Quellfunktion(x(j,i),y(j,i))+(wert_rechts+wert_unten)*a/hx^2;
  f(M,1)=1*Quellfunktion(x(j,i),y(j,i))+(wert_links+wert_oben)*a/hx^2;
  f(M,N)=1*Quellfunktion(x(j,i),y(j,i))+(wert_rechts+wert_oben)*a/hx^2;

Nun kann die rechte Seite in den Vektor   umgeformt werden. Des Weiteren fließt das   aus der Poissungleichung   ein.

  size (f) #rechte Seite kann in Vektor b umgeformt werden. Negativ wegen PG
  b=-1*reshape(f',N*M,1); %Quellfunktion in Spaltenvektor um Systemmatrix drauf zu werfen. (wird 
  transponiert, damit die Zeilen untereinander aufgestellt werden)
  %reshape funktioniert Spaltenmässig: es wird Sp1, dann Sp2, usw eingeordnet, wobei wir die Matrix f 
  nach Reihen/Zeilen einordnen.
  %Daher soll die Matrix f' mit N(Zeilen)x M(Spalten) in einen langen Vektor eingeordnet werden
  % LOESUNGSSCHRITT
  sol=BB\b;
  sol_matrix=reshape(sol,N,M);% Matrix mit N(Zeilen)x M(Spalten)
  sol_matrix=sol_matrix'; % Transponiert, wegen reshape


Graphische Ausgaben Im Folgenden sind die Bilder der Lösung und der Quellfunktion zu sehen.

  %Öffne ein Bildfenster und plotte die Lösung auf dem realen Koordinatenfeld
  figure(2);
  surfc(x,y,sol_matrix);
  title ("Loesung");
  ylabel("y")
  xlabel("x")
   
  %weiteres Bild mit Quellfunktion- rechte Seite des Systems
  figure(3);
  surfc(x,y,f);
  title ("Quellfunktion");
  ylabel("y")
  xlabel("x")

 

Implementierung der Neumann-Randbedingungen Bearbeiten

Nun werden die Dirichlet-Randbedingungen mit den Neumann-Randbedingungen kombiniert. Für die Neumannn-Randbedingungen müssen die Richtungsableitungen der Funktion   in Richtung des äußeren Normalenvektors gegeben sein:

 
 

Da wir auf einem rechteckigen Gebiet arbeiten gilt:

Es wird nun die Finite-Differenzen-Methode (FDM) für die Neumann-Randbedingung auf dem Rechteck   mit homogenen Randbedingungen mit   implementiert. Unser betrachtetes Gitter muss somit um die Randwerte erweitert werden:


  [x,y]=meshgrid(0:hx:xend,0:hy:yend);
  N=N+2;
  M=M+2;
  %konstanter Diffusionskoeffizient
  a=1.0;

Systemmatrix

Dadurch dass das Gitter erweitert wurde, gibt es nun weitere unbekannte Funktionswerte  . Der lange Vektor wird dann wie folgt aussehen:

 

Dabei entspricht die erste Spalte dem unterem Gitterrand, die letzte dem oberen. Außerdem wurden die Spaltenabschnitte um je zwei Punkte erweitert, wobei der erste auf dem linken Rand, der letzte auf dem rechten Rand liegt.

Die Dirichlet-Randbedingungen sollen nur an bestimmten Rändern durch Neumann-Randbedingungen ergänzt werden, jedoch nicht vollständig ersetzt, da sonst kein brauchbares Ergebnis herauskommt. Dies geschieht hier auf dem linken und rechten Rand. Das Gitter wird jedoch nicht darauf angepasst, wodurch ein kleiner Fehler entsteht.

Um das lineare Gleichungssystem   aufzustellen muss unsere blockdiagonale Matrix   um Einträge erweitert werden, damit  . Dabei wird der Diagonalblock   jeweils um eine Zeile oben und unten erweitert. Diese enstprechen den Werten des linken und rechten Randes, weshalb hier ein anderer Eintrag erfolgen muss. Dieser leitet sich aus dem Differenzenquotienten her.

   oder  

- linker Rand: den vorwärts -Differenzenquotient  

- rechter Rand: den rückwärts -Differenzenquotient  

- unterer Rand: den vorwärts -Differenzenquotient  

- oberer Rand: den rückwärts -Differenzenquotient  

siehe [7]

Die Systemmatrix sieht dann wie folgt aus:

  mit Diagonalblock   und null-erweiterter Einheitsmatrix  .

Zugehörige Octave-Implementierung

  Vec1=ones(N*M,1); % erzeugt Vektor der Länge N*M
  BB=diag(-4.*Vec1,0)+diag(ones(N*M-1,1),1)+ diag(ones(N*M-1,1),-1)+diag(ones(N*(M
  -1),1),N)+diag(ones(N*(M-1),1),-N);
  %Systemmatrix N^2xM^2 mit -4 auf der Diagonale und 1 auf den Nebendiagonalen und 1 auf den N und 
  -N-ter Nebendiagonale
  %Korrektur der Matrix (Blockdiagonalität)
  for i=1:(M-1)
  BB(i*N+1,i*N)=0;BB(i*N,i*N+1)=0;
  endfor
  % Matrix mit Diffkoeff/h^2 multiplizieren
  BB=BB*a/hx^2;

Um die obere und untere Zeile der Blockmatrizen zu ändern folgt:

  % Neumann RB für y: c* partial_y u=0 - einzelne Blöcke der Matrix ersetzen
  h=hx;
  block=diag((a/h)*ones(N,1));
  % Neumann RB für x: c* partial_x u=0 - einzelne Zeilen der Matrix ersetzen
  for i=1:(M-2)               #NRB linker und rechter Rand - einzelne Zeilen der
                              #Matrix ersetzen. oberste und unterste Zeile der Blockmatrix
  vector_up=zeros(1,N*M);     #Müssen geändert werden. Es werden die RB für rechts und
  vector_up(N*i+1)=a/h;       #links in die Systemmatrix eingepflegt. 
                              #a/h, denn a/h² *h (Matrix wurde schon mit a/h² multipliziert
  vector_up(N*i+2)=-a/h;
  vector_down=zeros(1,N*M);
  vector_down(N*i+N)=a/h;
  vector_down(N*i+N-1)=-a/h;
  BB(i*N+1,:)=vector_up ;    #Ersetzt entsprechende Zeile mit Vektor
  BB(i*N+N,:)=vector_down ;
  endfor

Matrixdarstellung

Stellt man das ganze als Matrix da, sieht es wie folgt aus: s. Bild Systemmatrix2

 
Systemmatrix2
  figure (4);
  %surface (BB);
  spy (BB);
  xlabel("Spalten")
  ylabel("Zeilen")
  zlabel("Matrix B")
  title ("Systematrix B");

rechte Seite des Systems

  for i=1:N
  for j=1:M
  f(j,i)=1*Quellfunktion(x(j,i),y(j,i));%*hx^2;
  %Neumann Randbedingung links und rechts:
  if i==1 f(j,i)=1*Quellfunktion(x(j,i),y(j,i)); 
  endif
  if i==N f(j,i)=1*Quellfunktion(x(j,i),y(j,i)); 
  endif
  %Dirichlet Randbedingung oben und unten:
  if j==1 f(j,i)=1*Quellfunktion(x(j,i),y(j,i))+wert_unten*a/hx^2; 
  endif
  if j==M f(j,i)=1*Quellfunktion(x(j,i),y(j,i))+wert_oben*a/hx^2; 
  endif
  endfor
  endfor

Ecken

Die Eckfunktionen werden folgendermaßen implementiert:

  f(1,1)=1*Quellfunktion(x(j,i),y(j,i));
  f(1,N)=1*Quellfunktion(x(j,i),y(j,i));
  f(M,1)=1*Quellfunktion(x(j,i),y(j,i));
  f(M,N)=1*Quellfunktion(x(j,i),y(j,i));
  size (f)
  b=-1*reshape(f',N*M,1);
  %reshape funktioniert Spaltenmässig: es wird Sp1, dann Sp2, usw eingeordnet, wobei wir die Matrix f 
  nach 
  Reihen/Zeilen einordnen.
  %Daher soll die Matrix f' mit N(Zeilen)x M(Spalten) in ein langen Vektor eingeordnet werden.
  % LOESUNGSSCHRITT:
  sol=BB\b;
  sol_matrix=reshape(sol,N,M);% Matrix mit N(Zeilen)x M(Spalten)
  sol_matrix=sol_matrix'; % Transponiert, wegen reshape

Graphik Graphisch sieht das ganze folgendermaßen aus: Zuerst ist wieder die Lösung und danach die Quellfunktion zu sehen.

  figure(5); 
  surfc(x,y,sol_matrix);
  title ("Loesung");
  ylabel("y")
  xlabel("x")

 

  %weiteres Bild mit Quellfunktion- rechte Seite des Systems
  figure(6);
  surfc(x,y,f);
  title ("Quellfunktion");
  ylabel("y")
  xlabel("x")

 

5. Übungsaufgabe SW10: Epidemiologische Modellierung als Reaktionsdiffusionsprozess mit FDM Bearbeiten

Arbeitsaufträge:

  • Implementierung FDM-Methode der Reaktionsdiffusionsgleichung für die zeitlich-räumliche Modellierung der Epidemie auf einem Rechteckgebiet   mit homogenen Neumannrandbedingungen  .
  • Ergänzung um geographisch differenzierte Bevölkerungsdichte. Funktion von Raumvariablen.
  • zusätzliche nicht konstanter Diffusionskoeffizient.

Modellierung Corona-Ausbreitung der Stadt Mainz Bearbeiten

Hierfür benötigen wir wie in der vorigen Aufgabe die Finite-Differenzen-Methode zur Lösung der Reaktionsdiffusionsgleichung

 
.


Wir betrachten in der Modellierung die Bevölkerungsdichte der Stadt Mainz Zentrum (Altstadt, Neustadt, Oberstadt und Hartenberg-Münchfeld).


Fläche: 98km² (wir haben diese auf 100km² aufgerundet um eine quadratische Fläche von 10kmx10km erstellen zu können). Bevölkerungsdichte: 6111,25 Einwohner/km²

Datei:Bild von Mainz.png
Bild von Mainz

Auf der Abbildung der Stadt Mainz kann man sehen, dass man die Stadt, wie oben schon erwähnt, grob als Quadrat ansehen.

  xend=10.0; %in km
  yend=10.0; %in km
  N=80; % Anzahl von Gitterpunkten in x-Richtung(0-te und N-te Index 
  entsprechen den Rändern, keine Gitterpunkte am Rand)
  a=0.01; %konstanter Diffusionskoeffizient
  T=450; %Zeitintervall in Tagen
  delta_t=0.03; %Zeitschritt

Um das Gitter zu konstruieren und um die   Gitterpunkte in gleichgroßem Abstand auf der Kante zu verteilen, bzw. den Abstand der Gitterpunkte zu berechnen muss die Kantenlänge des Quadrates durch   geteilt werden. Da ein Quadrat vorliegt, ist die Anzahl der Gitterpunkte in x- und y-Richtung gleich groß.

  hx=xend/(N+1) %Abstand Gitterpunkte/um Gitterpunkte im gleichen Abstand auf der Karte zu verteilen
  hy=hx; % setze so, damit sich Quadrate bilden 
  %M=floor((yend/hy))-1 -> Anzahl der Gitterpunkte in y-Richtung
  M=N; %Im Falle eines Quadrates, gleiche Anzahl an Gitterpunkten 
  Nr_timesteps=floor (T/delta_t) %Anzahl der Zeitschritte
Anfangswerte Bearbeiten
  B=6111.25; %Bevölkerungsdichte Einwohner pro Quadratkilometer in Mainz Zentrum (Altstadt, Neustadt, 
  Oberstadt, Hartenberg-Münchfeld),Durchschnittlich: 2236
  c=0.34; %Infektionsrate aus SIR-Abgabe3
  k=c./B; %Infektionsrate k.u.(B-u)
  w=1/14;%Wechselrate
Anfangsfunktion Bearbeiten
    function wert = initialfunction (x, y) #Quellfunktion
    wert = 0;
    r = 0.31;  # Fläche des Kreises: 0.3km^2 entspricht ca. 1833 Einwohnern 
    if sqrt ((x - 6.5) .^ 2 + (y - 6.5) .^ 2) <= r
   wert = 1 / (pi * r ^ 2); # Infektionen im Zentrum von Mainz (ein Infizierter)
  endif
  endfunction

Systemmatrix

Das erstellte Gitter muss (für die NRB) um die Randpunkte erweitert werden:

  [x,y]=meshgrid(0:hx:xend,0:hy:yend);
  N=N+2;
  M=M+2;

Die Systemmatrix wird nach dem gleichen Schema wie in Übungsaufgabe 4 erstellt:

  Vec1=ones(N*M,1); % erzeugt Vektor der Länge N*M
  BB=diag(-4.*Vec1,0)+diag(ones(N*M-1,1),1)+ diag(ones(N*M
  -1,1),-1)+diag(ones(N*(M-1),1),N)+diag(ones(N*(M-1),1),-N);
  % Systemmatrix N^2xN^2 mit -4 auf der Diagonale und 1 auf den 
  Nebendiagonalen und 1 auf den N und -N-ter Nebendiagonale
  %Korrektur der Matrix (Blockdiagonalität)
  for i=1:(M-1)
  BB(i*N+1,i*N)=0;BB(i*N,i*N+1)=0;
  endfor
  % Matrix mit Diffkoeff/h^2 multiplizieren
  BB=BB*a/hx^2;
homogene Neumann-Randbedingungen integrieren Bearbeiten

Bei den homogenen Neumann-Randbedingungen ist die Ableitung über den Rand  . Damit wird ein freier Fluss der Infektion in die angrenzenden Gebiete beschrieben. Für diese Randbedingungen werden jeweils die erste und letzte Blockzeile der Systemmatrix, welche dem oberen und unteren Rand entsprechen, angepasst. Auf dem linken und rechten Rand müssen die oberste und unterste Zeile der Diagonalblöcke der Systemmatrix ersetzt werden:

  % Neumann RB für y: a* partial_y u=0 - einzelne Blöcke der Matrix ersetzen
  block=diag((a/hx)*ones(N,1));
  %unterer Rand
  BB(1:N,1:N)=-block;
  BB(1:N,N+1:2*N)=block;
  %oberer Rand
  BB(N*(M-1)+1:N*M,N*(M-1)+1:N*M)=-block;
  BB(N*(M-1)+1:N*M,N*(M-2)+1:N*(M-1))=block;
  % Neumann RB f¸r x: a* partial_x u=0 - einzelne Zeilen der Matrix ersetzen
  for i=1:(M-2)
  vector_up=zeros(1,N*M);
  vector_up(N*i+1)=a/hx;
  vector_up(N*i+2)=-a/hx;
  vector_down=zeros(1,N*M);
  vector_down(N*i+N)=a/hx;
  vector_down(N*i+N-1)=-a/hx;
  BB(i*N+1,:) =-vector_up ; #Vektor der ersten Zeile
  BB(i*N+N,:) =-vector_down ; #Vektor der letzten Zeile
  endfor

Hieraus ergibt sich die folgende Systemmatrix (s.rechts):

 
Systemmatrixdarstellung
Anfangslösung in Matrix Bearbeiten

Die oben definierte Anfangslösung muss nun als Matrix aufgestellt werden und Infizierte müssen gesetzt werden.

  I0=1 % Anzahl der Anfangsinfizierungen pro gegebene Fläche pi*r^2
  for i=1:N
  for j=1:M
  initial(j,i)=I0*initialfunction(x(j,i),y(j,i));
  endfor
  endfor
  size (initial)
  sol_old=1*reshape(initial',N*M,1);
  %reshape funktioniert Spaltenmäßig: Sp1,Sp2, wir wollen Zeilenmäßig
  %Matrix f' ist N(Zeilen)x M(Spalten)
Grafik zur Einwohnerzahl implementieren Bearbeiten

In diesem Teil wird eine Grafik zur Einwohnerzahl

 
1 IÖR-Monitor Einwohnerzahl 2011 Raster 1000 m

als Bevölkerungsmatrix eingelesen. Wir haben uns für einen geeigneten Bildausschnitt für die Stadt Mainz entschieden:

 
Monitor Einwohnerzahl Bildausschnitt Mainz
  %Graphik einlesen und
  %Geeigneter Ausschnitt wählen für Mainz, Matrix A ist eine 3D Matrix
  A=imread ('Monitor einwohnerzahl zoom1.png');
  size(A); % Zeigt die Dimension der Bildmatrix
  S=A(83:92,105:114);
  imshow (S); % Bild wird angezeigt
  S=double(S);
  [s1 s2]=size(S);
  Max=max(max(S))
  S=(Max-S); % Farbumkehrung/ Anpassung

Anschließend werden die Werte der oben aufgestellten Matrix (10x10) an das am Anfang erstellte Gitter angepasst, denn die Matrizen sind unterschiedlich eingeteilt. Die Schritte des Gitters sind kleiner, als die der Matrix, weswegen die Matrix interpoliert werden muss:

 
Bevölkerungsdichte Mainz
  Sint=interp2(S,xend*(1*x.+2)/(xend+2),yend*(1*y.+2)/(yend+2), 
  'cubic'); 
  %y-Koordinate im Image läuft von oben nach unten, Bild flippen oben 
  <-> unten
  Sint=flipud (Sint);
  size (Sint)
  figure(67);
  surface(x,y, (B/Max)*Sint)
  title ("Bevoelkerungsdichte");
  ylabel("y")
  xlabel("x")
  colorbar
  %Skalierung auf max. Wert B-> Anpassung der Bevölkerungsdichte auf 
  die Karte
  %Korrektur der Bevölkerungsdichte (keine Null-Einträge) +0.1*Max 
  -> minimalen Wert der Bevölkerungsdichte setzen wir auf 10 % des 
  Maximum
  %Assemblierung der Matrix in ein Vektor
  B=reshape((B/Max)*Sint',N*M,1).+0.1*B; %Angepasste Bevölkerungsdichte
  size (B)

Dabei erhalten wir nun das Bild Bevölkerungsdichte Mainz. Vergleicht man den Bildausschnitt von Mainz mit dem Bild der gewählten Bevölkerungsdichte kann man schließen, dass die beiden Bilder annähernd übereinstimmen.

Reaktionsterm für kumulierte Infizierte Bearbeiten

In der nächsten Teilaufgabe sollten wir die Bevölkerungsdichte im Reaktionsterm geographisch differenziert als Funktion von Raumvariablen betrachten. Für die Berechnung der Dichte der kumulierten Infizierten werden folgende Funktionen benötigt:   (Rekationsterm)

  F=@(u) (c./B).*u.*(B.-u);


Zeitschleife

   for i=1:Nr_timesteps
  #Term F wird nun zu unserem System vom GDGL des räumlich diskretisierten NR-Problem für die Diffusion hinzugefügt.
  sol= sol_old+ BB*sol_old*delta_t + 1*F(sol_old)*delta_t;
  sol_old=sol;
  matrix_solution(:,i)=sol;
  endfor
  % Auswahl an Bildern drucken, jedes fünfzehnte Bild
  fig_index=floor([0.15:0.15:1]*Nr_timesteps)
  j=0
  for i=fig_index
  sol_matrix=reshape(matrix_solution(:,i),N,M);% Matrix mit N(Zeilen)x M(Spalten)
  sol_matrix=sol_matrix';
  disp(['Figure ',num2str(round(i/fig_index(1)))]);
  j=j+1;
  figure(j);
  % Alternativ surfc(x,y,sol_matrix*hx^2, "EdgeColor", "none") -> 3D
  surface(x,y,sol_matrix*hx^2, "EdgeColor", "none") % multipliziert mit hx^2, damit Anzahl der Infizierten pro 
  Rasterdargestellt wird (und nicht die Dichte)
  colormap ("jet")
  axis([0 xend 0 yend 0 1.1*max(max(B))*hx^2])
  colorbar
  title (["Loesung in t=", num2str(round(delta_t*i))]);
  ylabel("y")
  xlabel("x")
  test=["Fig_", num2str(j),".jpg"]
  endfor

Anfangslösung

  sol_matrix=reshape(matrix_solution(:,1),N,M);% Matrix mit N(Zeilen)x M(Spalten)
  sol_matrix=sol_matrix';
  disp(['Figure ',num2str(0)]);
  j=j+1;
  figure(j);
  %%%Alternativ surfc(x,y,sol_matrix*hx^2, "EdgeColor", "none")
  surface(x,y,sol_matrix*hx^2, "EdgeColor", "white")
  colormap ("jet")
  axis([0 xend 0 yend 0 1.1*max(max(B))*hx^2])
  colorbar
  title (['Loesung in t=', num2str(round(delta_t))]);
  ylabel("y")
  xlabel("x")

Die Abbildung zeigt, dass wir zu Beginn der Corona-Pandemie ca. einen Infizierten in Mainz haben:

  
 

 

Fazit

Die Legende gibt die Anzahl der kumulierten Infizierten pro Gitterpunkt an. Auf einem Gitterpunkt(Pixel) sind durchschnittlich 61 Einwohner. Wenn davon am Ende 45 Einwohner infiziert sind, sind das 2/3 aller Einwohner. Ab Tag 134 passiert nichts mehr. Hier ist schon der Höhepunkt erreicht und es infiziert sich niemand neues mehr.

Reaktionsterm für aktuell Infizierte Bearbeiten
 

Dafür wird die alte Lösung genutzt

  sol_old=1*reshape(initial',N*M,1); % Aktuell Infizierte
  sol_old_susp=B.-sol_old; % Susceptibles-Infektions-Anfällige


Unsere Slowdownfunktion aus Übungsaufgabe 3 wird ebenfalls benötigt:

  function val=slowdown4(x,t)
  % Ab Tag t (Argument der Funktion) wird die Infektionsrate in mehreren Schritten sinken:
  if x<t val=1 ; 
            else if x<t +8 val=t./(x.^1.1); 
            else if x<t +16 val=t./(x.^1.2); 
            else if x<t +51 val=t./(x.^1.3); 
            else if x<t +56 val=t./(x.^1.2);
            else if x<t +63 val=t./(x.^1.1);
            else if x<t +88 val=t./(x.^1);
            else if x<t +140 val=t./(x.^0.9);
            else if x<t +221 val=t./(x.^0.8);
            else if x<t +235 val=t./(x.^0.9);
            else if x<t +281 val=t./(x.^1);
            else if x<t +292 val=t./(x.^1.1);
            else if x<t +295 val=t./(x.^1);
            else if x<t +318 val=t./(x.^1.01);
            else if x<t +328 val=t./(x.^1.11);
            else if x<t +366 val=t./(x.^1.12);
            else if x<t +373 val=t./(x.^0.92); %Schulöffnungen + mehr Testungen
            else if x<t +377 val=t./(x.^0.91);
            else if x<t +390 val=t./(x.^0.92);
            else if x<t +393 val=t./(x.^0.93);
            else val=t./(x.^0.83) ;
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
                  endif
  endif
  if x> 418 val=0.2; endif

Reaktionsterm

  F=@(u,v,t) (c*slowdown4(25,t)./B).*u.*v;

Zeitschleife

  for i=1:Nr_timesteps #Die Zeitschleife erfolgt erneut mit Explizitem Eulerverfahren
  %zuerts nichtlin. F-tion des Reaktionsterms aus alten Werten ausrechnen, wir weiter benutzt:
  Reakt=F(sol_old,sol_old_susp, i*delta_t);
  %Erste Gleichung - für Susceptibles
  sol_susp= sol_old_susp+ BB*sol_old_susp*delta_t - Reakt*delta_t;
  %Zweite Gleichung - für Infected (aktuell), ( um Term -w*I erweitert)
  sol= sol_old+ BB*sol_old*delta_t+ (Reakt-w.*sol_old)*delta_t;
  %Speicherung für den nächsten Zeitschritt
  sol_old=sol;
  sol_old_susp=sol_susp;
  % Speicherung der aktuell Infizierten in einer Matrix, Speicherung der Anfälligen (S) nicht
  implementiert
  matrix_solution1(:,i)=sol;
  endfor

Animation

Anschließend erhalten wir mit dem gleichen Octave-Befehl wie im ersten Lösungsschritt unsere Animation für die aktuell Infizierten.

 

Zum Vergleich erfolgt hier noch die Graphik für die aktuell Infizierten ohne Slowdown-Funktion.

  1. https://de.wikiversity.org/wiki/Kurs:R%C3%A4umliche_Modellbildung
  2. https://de.wikiversity.org/wiki/Kurs:R%C3%A4umliche_Modellbildung/Aufgaben_Tutorium_SS2020
  3. https://de.wikipedia.org/w/index.php?title=Moore-Nachbarschaft&oldid=207626306
  4. https://de.wikiversity.org/wiki/Kurs:R%C3%A4umliche_Modellbildung/Gruppe_1
  5. https://de.wikipedia.org/wiki/Residuum_(numerische_Mathematik)
  6. https://de.wikipedia.org/wiki/St%C3%B6rgr%C3%B6%C3%9Fe_und_Residuum
  7. https://de.wikiversity.org/wiki/Numerische_Modellierung_der_Diffusion#Inhomogene_Randbedingungen