7.5 DRILL — ODE-oppgaver med roterende innpakning
Full drill på I/J/K-sjangrene: samme ODE-øvelse under skiftende vitenskapelig innpakning, slik at mønsteret gjenkjennes uansett kontekst.
Dette er drillkapitlet for Del 7 — ODE-oppgavene, altså «løs en differensiallikning numerisk». Tre sjangre møtes her:
- Sjanger J — ODE-system løst med det utleverte ODESolver-hierarkiet. Står i hvert eneste av de åtte gjennomgåtte avsluttende settene (100 prosent) og teller 9–10 poeng. Det er den tyngste enkeltoppgaven på et typisk sett.
- Sjanger I — skriv en ODE-løser som funksjon fra bunnen, typisk forlengs Euler. Kommer jevnlig og teller 5 poeng.
- Sjanger K — subklasse av ODESolver der du skriver kun advance. Topp-differensierende, 3–5 poeng.
Prioriteten er den høyeste boka har: dette må sitte. Sjanger J alene er verdt mer enn hele flervalgsskallet på et typisk sett.
Grunnen til at et helt kapittel går til drill, er at oppgaven er den samme hvert år, mens innpakningen roterer: et smitteutbrudd, en planetbane, en nervecelle, en værmodell, to bestander som spiser hverandre. Klarer du å oversette modellen til en høyreside f(t, u), er resten fire faste linjer.
Du besvarer alt som fritekst i Inspera, UiOs digitale eksamenssystem, uten hjelpemidler og uten å kunne kjøre koden. ODESolver-modulen leveres derimot som vedlegg, og du skal bruke den — ikke skrive den.
Kapitlet har tre deler: én løsningsoppskrift på sju steg, ett gjennomarbeidet eksamenscase med sensorkommentar ved hvert steg, og ti oppgaver på eksamensnivå med roterende innpakning.
Om delpoeng: sensor gir uttelling for hvert steg for seg — høyresidens signatur, utpakkingen av tilstandsvektoren, returtypen, de tre kallene på løseren, utpakkingen av kolonnene, plottet. Riktig ODE-oppsett belønnes selv med en indeksfeil eller en glemt etikett.
Sist du var her
Drillen forutsetter hele Del 7: kap. 7.1 (egen forlengs-Euler-funksjon), kap. 7.2 (bruk av hierarkiet), kap. 7.3 (systemer) og kap. 7.4 (subklasser). Her er de tre grepene du kommer til å bruke i hver eneste oppgave, oppfrisket med kjørt utskrift.
1. Egen løser som funksjon (sjanger I). N skritt, N+1 punkter, startverdien før løkka.
import numpy as np
def forward_euler(f, T, N, u0):
t = np.linspace(0, T, N+1)
u = np.zeros_like(t)
u[0] = u0
dt = t[1] - t[0]
for n in range(N):
u[n+1] = u[n] + dt*f(t[n], u[n])
return t, u
def f(t, u):
return -0.5*u
t, u = forward_euler(f, 4.0, 40, 3.0)
print(len(t), f'{u[-1]:.6f}', f'{3*np.exp(-2):.6f}')Utskrift:
41 0.385536 0.406006Med bare 40 skritt er forlengs Euler nesten fem prosent unna. Det er metodens feil, ikke kodens.
2. Det utleverte hierarkiet (sjanger J). Tre kall: konstruktør, startbetingelse, solve.
import numpy as np
from ODESolver import RungeKutta4
def f(t, u):
return -0.5*u
solver = RungeKutta4(f)
solver.set_initial_condition(3.0)
t, u = solver.solve((0, 4), 40)
print(len(t), f'{u[-1]:.6f}', f'{3*np.exp(-2):.6f}')Utskrift:
41 0.406006 0.406006Samme antall skritt, seks riktige desimaler. Det er derfor RungeKutta4 er standardvalget når oppgaven ikke sier noe annet.
3. Systemer. Pakk ut u i høyresiden, returner en liste, og pakk ut kolonnene etterpå.
import numpy as np
from ODESolver import RungeKutta4
def f(t, u):
x, y = u
return [y, -x]
solver = RungeKutta4(f)
solver.set_initial_condition([1.0, 0.0])
t, u = solver.solve((0, 6), 600)
x, y = u[:, 0], u[:, 1]
print(u.shape)
print(f'{x[-1]:.6f} {np.cos(6):.6f}')Utskrift:
(601, 2)
0.960170 0.960170Formen (601, 2) sier alt: 601 tidspunkter i radene, 2 komponenter i kolonnene. Er noe av dette uklart, les kap. 7.3 først — drillen forklarer ikke konstruksjonene på nytt.
Forkunnskaper
- Egen forlengs-Euler-løser som funksjon (sjanger I): kap. 7.1.
- Det utleverte ODESolver-hierarkiet og de tre kallene: kap. 7.2.
- ODE-systemer: høyresiden f(t, u) og utpakking av kolonnene: kap. 7.3.
- Subklasse av ODESolver med advance (sjanger K): kap. 7.4.
- NumPy-tabeller, np.zeros og np.linspace: kap. 4.1.
- Plotting med label= og plt.legend(): kap. 4.3.
Les modellen i oppgaven, og gjør så dette, i rekkefølge.
1. Identifisér tilstandsvariablene. Hvor mange størrelser endrer seg over tid? Det er antall likninger, antall komponenter i u, og antall kolonner i svaret.
2. Skriv høyresiden def f(t, u): — tiden først. Første linje pakker ut: S, E, I, D = u. Deretter én linje per derivert, og return [dS, dE, dI, dD] som liste, i samme rekkefølge som utpakkingen.
3. Sett parametrene som variabler over funksjonen, eller lagre dem i en klasse med __call__(self, t, u) hvis oppgaven ber om det. Løseren kaller f med bare to argumenter, så parametrene kan ikke sendes inn.
4. Sett u0 som en liste av startverdier, i samme rekkefølge som utpakkingen.
5. De tre kallene: solver = RungeKutta4(f), solver.set_initial_condition(u0), t, u = solver.solve((0, T), N). Merk at t_span er én tuppel, altså ett argument.
6. Pakk ut kolonnene: S, E, I, D = u[:, 0], u[:, 1], u[:, 2], u[:, 3]. u[k] er hele tilstanden ved tidspunkt k — noe helt annet.
7. Plott: ett plt.plot(t, komponent, label='navn') per kurve, aksenavn, plt.legend(), plt.show(). Beskriv figuren i ord hvis oppgaven ber om det.
Skjelettet er alltid dette, og det er verdt å skrive ned først, før du fyller inn modellen:
from ODESolver import RungeKutta4
def f(t, u):
x, y = u
dx = 0.0
dy = 0.0
return [dx, dy]
solver = RungeKutta4(f)
solver.set_initial_condition([2.0, 5.0])
t, u = solver.solve((0, 10), 100)
print(u.shape, u[-1, 0], u[-1, 1])Utskrift:
(101, 2) 2.0 5.0Skjelettet gir uttelling i seg selv — her står begge komponentene stille, fordi de deriverte er null. Fyller du inn modellen feil, mister du ett eller to poeng; glemmer du skjelettet, mister du oppgaven.
ODE-oppgavene kommer med ODESolver-hierarkiet som vedlegg, og grensesnittet har endret seg over tid. Bokas standard, og formen som gjelder fra 2023, er:
- høyresiden skrives f(t, u) — tid først
- løseren kalles solver.solve((0, T), N) — et tidsintervall som tuppel, og antall skritt
I eldre sett (2020–2022) var rekkefølgen omvendt i høyresiden, f(u, t), og solve tok én liste med ferdig utregnede tidspunkter i stedet for intervall og antall. Begge variantene er gjengitt i kap. 7.2, i collapsiblen «Den utleverte ODESolver-modulen».
Praktisk regel på eksamen: bruk to minutter på å lese vedleggets solve-signatur og advance-metode før du skriver noe. To minutter kan redde en tipoengsoppgave.
Den lumske delen er at feil argumentrekkefølge i f ikke alltid gir feilmelding. Bruker høyresiden bare u og ikke t — som de fleste modellene i dette kapitlet gjør — kjører programmet fint og gir feil svar. Skriv derfor signaturen av vedlegget, ikke av hukommelsen.
Attributtnavnene kan også variere. Trenger du steglengden inne i en subklasse og self.dt ikke finnes, virker dt = self.t[self.n+1] - self.t[self.n] uansett.
u[:, k] er komponent k gjennom hele tiden; u[k] er hele tilstanden ved tidspunkt k. Blander du dem, plotter du fire punkter i stedet for fire kurver — og figuren ser tom ut.Høyresiden returnerer noe annet enn en liste. For et system skal return [dS, dI, dR] — ikke tre separate verdier, ikke et tuppel av arrayer, og ikke bare den første. Rekkefølgen i lista må være den samme som i utpakkingen.
#1 — av-én på antall punkter. N skritt gir N+1 punkter. Det gjelder både i din egen forward_euler og i det utleverte hierarkiet: solve((0, T), 100) gir et t med 101 elementer.
set_initial_condition med flere argumenter. For et system er startverdien én liste: solver.set_initial_condition([49980, 20, 0, 0]). Fire separate argumenter gir TypeError.
Glemt label= eller plt.legend(). Figuren tegnes pent, men ingen ser hvilken kurve som er hvilken. Det koster et halvt til ett poeng hver gang, og det er den billigste feilen å unngå på hele settet.
Rekursjon er utenfor pensum i IN1900. Et ODE-steg som avhenger av det forrige frister til å la en funksjon kalle seg selv; det er utenfor pensum, markeres uønsket i de offisielle løsningsforslagene, og gir dessuten ingen tabell å plotte. Løkka — eller det utleverte hierarkiets løkke — er den forventede løsningen.
Det gjennomarbeidede caset (~20 min)
Under står en komplett sjanger-J-oppgave av samme type og vekt som på et virkelig sett, med sensorkommentar ved hvert steg.
Oppgaven (10 poeng). Et utbrudd i en befolkning på modelleres med fire grupper: mottakelige , eksponerte (smittet, men ikke smittsomme ennå), smittsomme og gjennomgått . Modellen er
med , og . Ved er , og . Tiden måles i døgn. Du har ODESolver-modulen med ForwardEuler og RungeKutta4 tilgjengelig.
a) (4 p) Skriv høyresiden f(t, u).
b) (3 p) Skriv koden som løser systemet fra til med 2000 skritt ved hjelp av RungeKutta4, og pakker ut de fire komponentene.
c) (3 p) Skriv plottekoden og beskriv figuren.
Del (a), 4 poeng: skriv f(t, u). Del (b), 3 poeng: løs systemet og pakk ut komponentene.
Gå gjennom oppskriften. Fire tilstandsvariabler gir fire likninger, fire komponenter i u og fire kolonner i svaret. Parametrene settes som variabler over funksjonen — løseren kaller f med bare to argumenter, så de kan ikke sendes inn.
Legg merke til navnet N_tot på befolkningsstørrelsen. Bokstaven N er allerede opptatt av antall skritt i solve, og de to må ikke blandes.
N_tot = 50000
beta = 0.45
sigma = 0.2
gamma = 0.14
def f(t, u):
S, E, I, D = u
dS = -beta*S*I/N_tot
dE = beta*S*I/N_tot - sigma*E
dI = sigma*E - gamma*I
dD = gamma*I
return [dS, dE, dI, dD]
print(f(0, [49980, 20, 0, 0]))Utskrift:
[-0.0, -4.0, 4.0, 0.0]Kontrollen ved er verdt de ti sekundene den tar. Med smittes ingen ennå, så den første komponenten er null. De 20 eksponerte blir smittsomme med rate , altså 4 personer per døgn — derfor i den andre komponenten og i den tredje. Og ingen har gjennomgått sykdommen ennå, så den fjerde er null.
Del (b). De tre kallene, og deretter utpakkingen. For et system er u todimensjonalt: rad n er tilstanden ved tidspunkt n, kolonne k er komponent nummer k.
import numpy as np
from ODESolver import RungeKutta4
N_tot = 50000
beta = 0.45
sigma = 0.2
gamma = 0.14
def f(t, u):
S, E, I, D = u
return [-beta*S*I/N_tot, beta*S*I/N_tot - sigma*E, sigma*E - gamma*I, gamma*I]
solver = RungeKutta4(f)
solver.set_initial_condition([49980, 20, 0, 0])
t, u = solver.solve((0, 200), 2000)
S, E, I, D = u[:, 0], u[:, 1], u[:, 2], u[:, 3]
print('u.shape =', u.shape)
print(f'maks I = {I.max():.1f} paa dag {t[I.argmax()]:.1f}')
print(f'slutt: S = {S[-1]:.1f} E = {E[-1]:.1f} I = {I[-1]:.1f} D = {D[-1]:.1f}')
print(f'sum = {S[-1]+E[-1]+I[-1]+D[-1]:.1f}')Utskrift:
u.shape = (2001, 4)
maks I = 9339.2 paa dag 67.8
slutt: S = 2333.5 E = 0.0 I = 0.1 D = 47666.4
sum = 50000.0Tre kontroller verdt å gjøre på eksamen. Formen er (2001, 4): 2000 skritt gir 2001 punkter, og fire kolonner fordi systemet har fire likninger. Summen av komponentene er 50 000 hele veien, som den skal være når ingen forsvinner ut av modellen. Og toppen i I kommer rundt dag 68.
Sensorkommentar del (a), steg for steg:
- Signaturen def f(t, u): med tiden først — 1 p. Dette er stedet API-forvekslingen (#14) slår til.
- Utpakkingen S, E, I, D = u som første linje — 1 p.
- De fire uttrykkene — 1 p. Bommer du på ett ledd, får du halve.
- return [dS, dE, dI, dD] som liste, i samme rekkefølge som utpakkingen — 1 p. Returnerer du et tall eller en tuppel av feil lengde, faller hele oppgaven.
Sensorkommentar del (b):
- RungeKutta4(f) — 1 p.
- set_initial_condition med én liste av fire startverdier — 1 p. Fire separate argumenter gir TypeError.
- solve((0, 200), 2000) med tuppelen som ett argument, og utpakkingen med u[:, k] — 1 p.
Hva som er godt nok. Skriver du de fire uttrykkene i egne variabler først, som i den øverste blokka, er det like riktig og lettere å lese. Bruker du ForwardEuler i stedet for RungeKutta4 fordi oppgaven ikke sier noe, mister du ingenting — men si i en kommentar hvorfor du valgte.
Del (c), 3 poeng: plott de fire kurvene i samme figur, med forklaring, og beskriv figuren.
Fire plot-kall med label=, ett legend(). Komponentene kan plottes direkte fra u uten å pakkes ut først:
import matplotlib.pyplot as plt
from ODESolver import RungeKutta4
N_tot = 50000
beta = 0.45
sigma = 0.2
gamma = 0.14
def f(t, u):
S, E, I, D = u
return [-beta*S*I/N_tot, beta*S*I/N_tot - sigma*E, sigma*E - gamma*I, gamma*I]
solver = RungeKutta4(f)
solver.set_initial_condition([49980, 20, 0, 0])
t, u = solver.solve((0, 200), 2000)
plt.plot(t, u[:, 0], label='S mottakelige')
plt.plot(t, u[:, 1], label='E eksponerte')
plt.plot(t, u[:, 2], label='I smittsomme')
plt.plot(t, u[:, 3], label='D gjennomgatt')
plt.xlabel('tid (dogn)')
plt.ylabel('antall personer')
plt.legend()
plt.show()
print(f'{len(t)} punkter')Utskrift:
2001 punkterFiguren i ord. Førsteaksen viser tid fra 0 til 200 døgn, andreaksen antall personer fra 0 til 50 000. Kurven for mottakelige starter øverst i nesten 50 000, ligger nesten flat de første tretti døgnene, faller deretter bratt gjennom dag 50 til 90, og flater ut rundt 2300. Kurven for eksponerte og kurven for smittsomme er begge klokkeformede: de starter nær null, vokser eksponentielt, og har topper på henholdsvis rundt 7420 (dag 62) og 9340 (dag 68) — der de eksponerte topper seg knapt seks døgn før de smittsomme, siden man må være eksponert før man blir smittsom. Kurven for gjennomgått stiger monotont fra null og flater ut rundt 47 700. Toppen i smittsomme ligger der kurven for mottakelige er brattest. Forklaringen navngir de fire kurvene.
Sensorkommentar del (c): fire plot-kall med riktige kolonner (1 p) · label= på alle fire pluss legend() (1 p) · aksenavn, show() og en figurbeskrivelse med topper og retning (1 p).
Den ene dyre feilen er å skrive plt.plot(t, u[0]) i stedet for plt.plot(t, u[:, 0]). Det første er hele tilstanden ved tidspunkt 0 — fire tall — og plottekallet feiler eller tegner noe meningsløst. Skriv utpakkingen én gang og bruk variabelnavnene etterpå, så unngår du det.
— naturlig pausepunkt —
Oppgaver: samme mønster, ny innpakning (~35 min for oppgave 1–5)
Alle oppgavene under er på eksamensnivå. Innpakningen roterer bevisst mellom biologi, mekanikk, fysiologi og meteorologi. Bruk oppskriftens sju steg på hver oppgave før du skriver en linje kode — det første spørsmålet er alltid «hvor mange tilstandsvariabler?».
med per time og .
a) Skriv forward_euler(f, T, N, u0) fra bunnen. Den skal returnere t og u.
b) Løs på med 600 skritt. Skriv ut antall punkter, steglengden, startverdien, verdien etter 10 timer og sluttverdien.
c) Hvor mange punkter har løsningen, og hvorfor?
Ved er planeten i med farten . Da er banen en sirkel med omløpstid .
a) Skriv høyresiden f(t, u) med fire komponenter.
b) Løs ett helt omløp med RungeKutta4 og 2000 skritt, og skriv ut formen på u, start- og sluttposisjon, og avstanden til stjernen ved slutten.
c) Hva er fornuftssjekken her, og hva ville det betydd om avstanden ikke var 1?
der er membranpotensialet, er en tilbakestillingsvariabel, og , , og er den ytre strømmen.
a) Skriv høyresiden f(t, u).
b) Løs på med 4000 skritt fra , , og skriv ut formen på u samt største og minste verdi av begge komponentene.
c) Hvorfor kan ikke parameteren sendes inn som et tredje argument til f, og hva er de to lovlige måtene å håndtere den på?
Oppgave 2 testet steg 1 og 2 i den formen som skiller: en annenordens likning gjort om til fire førsteordens. Kjenner du igjen mønsteret «posisjon og fart», er de to første deriverte alltid de to siste variablene.
Oppgave 3 testet steg 3, altså hvor parametrene bor. Spørsmålet «hvorfor kan ikke parameteren sendes inn?» kommer igjen og igjen, fordi det tvinger fram forståelsen av at f kalles av løseren, ikke av deg.
Legg merke til at alle tre oppgavene har en fornuftssjekk innebygd: den logistiske veksten skal flate ut mot bæreevnen, planetbanen skal ha konstant radius, og nervecellen skal svinge. Har du ingen fasit, er slike sjekker det eneste du har.
a) Skriv subklassen Midtpunkt(ODESolver) med kun advance.
b) Sammenlign den med ForwardEuler på , , over med bare 10 skritt. Den eksakte løsningen er .
c) Hvorfor skal du bare skrive advance, og ikke hele klassen?
Problemet er stivt: forlengs Euler krever ekstremt små skritt for å holde seg i ro.
a) Skriv subklassen BaklengsEuler(ODESolver). Hvert skritt løser likningen for den nye verdien , med root fra scipy.optimize.
b) Sammenlign med ForwardEuler over med bare 10 skritt. Den eksakte løsningen er .
c) Hvorfor må tiden i likningen være og ikke ?
Oppgave 6–10: sporing, feilsøking og de fulle settoppgavene (~35 min)
— naturlig pausepunkt —
De neste fem oppgavene dekker de øvrige formene ODE-stoffet tar på et sett: en sporingsoppgave fra flervalgsskallet, en «hvilken linje mangler», en «finn feilen», en påstandstabell, og en full tipoengsoppgave.
(Midtveisnivå, sjanger A — kodesporing, altså «hva skriver dette programmet ut?».) Hva skriver programmet ut? NumPy skriver tabeller uten komma. Løseren er den utleverte ForwardEuler.
import numpy as np
from ODESolver import ForwardEuler
def f(t, u):
return t - u
solver = ForwardEuler(f)
solver.set_initial_condition(1.0)
t, u = solver.solve((0, 1), 4)
print(u)
print(len(t), t[1] - t[0])(Midtveisnivå, sjanger E — «hvilken linje mangler?». Sjanger E er flervalgstypen der ett kall eller én linje er fjernet fra et ellers riktig program.) Programmet skal løse et system med to likninger. Én linje er fjernet.
from ODESolver import RungeKutta4
def f(t, u):
x, y = u
return [y, -4*x]
solver = RungeKutta4(f)
# HER MANGLER ÉN LINJE
t, u = solver.solve((0, 10), 500)
x, y = u[:, 0], u[:, 1]Hvilken linje hører på plassen?
a) solver.u0 = [1.0, 0.0]
b) solver.set_initial_condition(1.0, 0.0)
c) solver.set_initial_condition([1.0, 0.0])
d) solver.solve([1.0, 0.0])
Programmet skal løse rovdyr–byttedyr-systemet , fra over med 1200 skritt, og plotte begge bestandene. Det har fire feil.
from ODESolver import RungeKutta4
import matplotlib.pyplot as plt
def f(u, t):
x, y = u
return 0.4*x - 0.02*x*y, 0.01*x*y - 0.3*y
solver = RungeKutta4(f)
solver.set_initial_condition(40, 9)
t, u = solver.solve((0, 60), 1200)
plt.plot(t, u[0])
plt.plot(t, u[1])
plt.show()a) Nevn de fire feilene og si hva hver av dem fører til.
b) Skriv den rettede koden.
(Midtveisnivå, sjanger D — «hvilke av påstandene er riktige?». Sjanger D er matche-typen der du avgjør om hver påstand holder.) Et system med tre likninger løses med t, u = solver.solve((0, 20), 400).
Avgjør for hver påstand om den er riktig eller gal.
| Rad | Påstand |
|---|---|
| 1 | t har 401 elementer |
| 2 | u har formen (401, 3) |
| 3 | u[:, 1] er komponent nummer 1 gjennom hele tiden |
| 4 | u[5] er komponent nummer 5 gjennom hele tiden |
| 5 | Steglengden er 0,05 |
| 6 | solve kan kalles uten set_initial_condition først |
med , og .
a) (4 p) Skriv høyresiden f(t, u).
b) (3 p) Løs på med 6000 skritt fra med RungeKutta4. Skriv ut formen på u og ytterverdiene for og .
c) (2 p) Kjør på nytt med startverdien og sammenlign sluttverdien for .
d) (1 p) Hva forteller resultatet i c) om værvarsling?
advance og ingenting annet.Oppgave 5 testet den implisitte varianten, som er nivå 3-stoffet i Del 7. Signalet er ordet stiv, eller at oppgaven ber om baklengs Euler. Da skal root inn, og tiden skal være .
Oppgave 6 var ODE-stoffet slik det ser ut på midtveiseksamen: ingen kode skal skrives, bare spores. Steglengden og antall punkter er hele temaet.
Oppgave 7 var sjanger E, den billigste oppgavetypen på settet: ett poeng, tretti sekunder, og de tre faste kallene er alt du trenger å huske.
Oppgave 8 testet feilkatalogen baklengs. De fire du skal kjenne igjen på et blunk er argumentrekkefølgen i f, returtypen, antall argumenter til set_initial_condition, og u[k] mot u[:, k].
Oppgave 9 var påstandstabellen. Fire av seks rader handler om telling og indeksering — det er der poengene ligger i denne sjangeren.
Oppgave 10 var den fulle tipoengsoppgaven, med en avsluttende «forklar hva du ser». Den siste deloppgaven kan besvares selv om koden ikke virker, og du skal alltid skrive noe der.
Begrepsbank
Begrepsbanken er flashcard-/repetisjonsstoff — den gjentar det du nettopp har lest. Hopp trygt over ved førstegangslesing; tidsanslaget for kapitlet gjelder kjernestoffet.
ODE-system løst med det utleverte hierarkiet. Står i 8 av 8 gjennomgåtte avsluttende sett og teller 9–10 poeng — den tyngste enkeltoppgaven på et typisk sett. Innpakningen roterer mellom epidemi, populasjonsdynamikk, mekanikk, nervecelle og vær; kodemønsteret er identisk.
Sjanger I er å skrive ODE-løseren selv som en funksjon, typisk forlengs Euler, og teller 5 poeng. Sjanger K er å lage en subklasse av ODESolver der du bare skriver advance, og teller 3–5 poeng. Signalordene i oppgaveteksten er «skriv en funksjon som løser» for I og «utvid hierarkiet» for K.
Antall størrelser som endrer seg over tid er antall likninger, antall komponenter i u, antall elementer i startlista og antall kolonner i svaret. Alt henger sammen, og tellingen gjøres én gang før du skriver noe.
def f(t, u): med tiden først, utpakking som første linje, én linje per derivert, og return som liste i samme rekkefølge som utpakkingen. Argumentet t skal stå der selv om modellen ikke bruker det.Løseren kaller f med nøyaktig to argumenter, så parametrene kan ikke sendes inn. De to lovlige måtene er variabler over funksjonen, eller en klasse med __init__ som lagrer dem og __call__(self, t, u) som regner.
RungeKutta4(f), set_initial_condition(u0), solve(t_span, N). Rekkefølgen er fast, t_span er én tuppel, og set_initial_condition tar ett argument — en liste for et system.u[:, k] er komponent k gjennom hele tiden, altså kurven du plotter. u[k] er hele tilstanden ved tidspunkt k, altså like mange tall som systemet har likninger. Å blande dem er den vanligste feilen i sjanger J, og den gir en figur som ser tom ut.solve((0, T), N) gir N skritt og N+1 punkter, og u.shape er (N+1, antall likninger). Samme telling gjelder i din egen løser: np.linspace(0, T, N+1) og range(N).Bokstandard er f(t, u) og solve((0, T), N). I eldre sett var det f(u, t) og solve(time_points). Feil argumentrekkefølge gir ofte ingen feilmelding, fordi mange høyresider ikke bruker t — les vedlegget hvert år.
Klasselinja class Ny(ODESolver):, def advance(self): uten andre argumenter, hentelinja med korte lokale navn, og formelen med return. Basisklassen gjør tilordningen til self.u selv — advance skal bare returnere neste verdi.
Baklengs Euler bruker stigningstallet ved punktet du skal til, altså . Siden er den ukjente, defineres en indre funksjon som er null i løsningen, og root løser den med forrige verdi som startgjetning. Svaret ligger i sol.x, som alltid er et array.
Summen av komponentene i en lukket modell skal være konstant. En sirkelbane skal ha konstant radius. En løsning som skal dø ut, skal nærme seg null. Slike sjekker er alt du har på en hjelpemiddelfri eksamen, og det er verdt et poeng å nevne dem.
Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.
Skolesaga er en uavhengig læringsressurs og er ikke tilknyttet eller godkjent av Universitetet i Oslo. Dette er ikke offisielt studiemateriell. Les mer.