Demo 10: Vektorfelter og deres integration langs kurver (det tangentielle kurveintegral)#
Demo af Christian Mikkelstrup, Hans Henrik Hermansen, Jakob Lemvig, Karl Johan Måstrup Kristensen og Magnus Troen. Revideret marts 2026 af shsp.
from sympy import *
from dtumathtools import *
init_printing()
Vektorfelter#
Som enhver anden vektorfunktion kan vektorfelter defineres enten som et Sympy-udtryk,
x, y, z = symbols("x,y,z", real=True)
V = Matrix([y * cos(x), y * sin(x), z])
V
eller som en Python-funktion, fx som en lambda-funktion:
V = lambda x, y, z: Matrix([y * cos(x), y * sin(x), z])
V(x, y, z)
Du vil også få brug for at indsætte parameterfremstillinger, som i sig selv er vektorfunktioner, ind i vektorfelter, og til det formål er sidstnævnte af de to ovennævnte definitioner nemmest at arbejde med. En parameterkurve,
r1, r2, r3 = symbols("r1,r2,r3", cls=Function)
t = symbols("t")
r = Matrix([r1(t), r2(t), r3(t)])
indsættes nemt i vektorfeltet ved:
V(*r)
På den anden side kan det være trættende at skulle taste V(x,y,z) hver eneste gang, du skal bruge vektorfeltet, og førstnævnte gør det nemt blot at taste V.
Vektorfelter plottes let. Bemærk, hvordan vi style’r pilene:
vectorfield_V = dtuplot.plot_vector(
V(x,y,z),
(x, -1, 1),(y, -1, 1),(z, 0, 6),
n=5,
quiver_kw={"alpha": 0.5, "length": 0.1, "color": "black"},
colorbar=False
)
Hvis du får brug for at beregne flere af et vektorfelts egenskaber som fx rotationen eller divergensen, så findes der dertilegnede kommandoer i dtumathtools-pakken:
rotV = dtutools.rot(V(x, y, z), (x, y, z))
rotV
divV = dtutools.div(V(x, y, z), (x, y, z))
divV
Det tangentielle kurveintegral#
Betragt vektorfeltet
samt de to kurver \({\mathcal K}_1\) og \({\mathcal K}_2\) med parameterfremstillingerne
hvor \(u \in [0,4\pi]\) for begge.
x, y, z, u = symbols("x y z u", real=True)
r1 = Matrix([cos(u), sin(u), u / 2])
r2 = Matrix([1, 0, u / 2])
V = Matrix([-y, x, 2 * z])
u_interval = (u, 0, 4 * pi)
\(\boldsymbol r_1\) tegner et stykke af en heliks (eller skruelinje), mens \(\boldsymbol r_2(u)\) tegner et lodret linjestykke. Bemærk, at de begge starter i \(A = (1,0,0)\) og ender i \(B = (1,0,2\pi)\). Her er et samlet plot:
K1 = dtuplot.plot3d_parametric_line(
*r1, u_interval, show=False, rendering_kw={"color": "red"}, colorbar=False
)
K2 = dtuplot.plot3d_parametric_line(
*r2, u_interval, show=False, rendering_kw={"color": "blue"}, colorbar=False
)
vektorfelt_V = dtuplot.plot_vector(V,(x, -1, 1),(y, -1, 1),(z, 0, 6),
n=5,
quiver_kw={"alpha": 0.5, "length": 0.1, "color": "black"},
colorbar=False,
show=False,
)
kombineret = K1 + K2 + vektorfelt_V
kombineret.legend = False
kombineret.show()
Vi vil nu beregne det tangentielle kurveintegral af \(\pmb{V}\) langs hver af de to kurver fra \(A\) til \(B\). Lærebogen giver os følgende formel (hvor \(a\) og \(b\) er de \(u\)-værdier, der svarer til hhv. punkterne \(A\) og \(B\), altså \(A=\boldsymbol r(a),B=\boldsymbol r(b)\)):
Først tangentvektorerne:
r1d = r1.diff(u)
r2d = r2.diff(u)
r1d, r2d
Så integranderne, som er prikprodukter:
integrand1 = V.subs({x: r1[0], y: r1[1], z: r1[2]}).dot(r1d)
integrand2 = V.subs({x: r2[0], y: r2[1], z: r2[2]}).dot(r2d)
integrand1.simplify(), integrand2.simplify()
Det tangentuelle kurveintegral langs \({\mathcal K}_1\) findes altså som \(\displaystyle\int_{{\mathcal K}_1} \pmb{V} \cdot \mathrm{d}\pmb{s} = \int_0^{4\pi} \frac{u}{2} + 1 \,\mathrm{d}u\), og langs \({\mathcal K}_2\) findes det som \(\displaystyle\int_{{\mathcal K}_2} \pmb{V} \cdot \mathrm{d}\pmb{s} = \int_0^{4\pi} \frac{u}{2} \,\mathrm{d}u\):
Tan_K1=integrate(integrand1, (u, 0, 4 * pi))
Tan_K2=integrate(integrand2, (u, 0, 4 * pi))
Tan_K1,Tan_K2
Vi får ikke samme resultat, hvilket betyder, at det tangentielle kurveintegral afhænger af ruten. Lærebogen fortæller om konsekvenserne af dette, fx at \(\boldsymbol V\) dermed ikke kan være et gradientvektorfelt (dvs., at den ikke har nogen stamfunktion).
Gradientvektorfelter og stamfunktionsbestemmelse#
Hvis et glat vektorfelt er et gradientvektorfelt, så fortæller lærebogen os at:
det har en stamfunktion (altså, en funktion som den er gradient for).
et tangentielt kurveintegral af det langs enhver kurve fra origo til et vilkårligt punkt \(\pmb{x}\) vil være en stamfunktion.
tangentielle kurveintegraler af det er uafhængige af ruten.
Det er altså brugbart at vide, om et vektorfelt er et gradientvektorfelt. Vi kan undersøge, om det er tilfældet, ved at beregne det tangentielle kurveintegral langs en hvilken som helst kurve, hvorefter vi kan tjekke, om første punkt i listen er opfyldt. Da vi kan vælge en hvilken som helst rute, er et ofte-benyttet valg en såkaldt trappelinje.
Trappelinjemetoden#
Lad os betragte et glat vektorfelt i \(\Bbb R^3\):
Ved trappelinjen \({\mathcal T}\) fra origo \(\pmb{x}_0=(0,0,0)\) til et vilkårligt punkt \(\pmb{x}=(x,y,z)\) menes der ruten, du ville følge, hvis du skulle gå langs med \(x\)-aksen, så langs \(y\)-aksen og så langs \(z\)-aksen. Disse tre stykker er akseparallelle rette linjer og derfor nemme at parametrisere:
r1 = Matrix([u, 0, 0])
r2 = Matrix([x, u, 0])
r3 = Matrix([x, y, u])
For \((x,y,z)=(1,1,1)\) som et eksempelpunkt kan vi plotte trappelinjen:
u_range = (u, 0, 1)
# Trappelinjens trin
p1 = dtuplot.plot3d_parametric_line(u, 0, 0, u_range, show=False, rendering_kw={"color": "red"}, colorbar=False)
p2 = dtuplot.plot3d_parametric_line(1, u, 0, u_range, show=False, rendering_kw={"color": "red"}, colorbar=False)
p3 = dtuplot.plot3d_parametric_line(1, 1, u, u_range, show=False, rendering_kw={"color": "red"}, colorbar=False)
# Punktet
xyz = dtuplot.scatter(Matrix([1, 1, 1]), show=False, rendering_kw={"color": "black"})
kombineret = p1 + p2 + p3 + xyz
kombineret.legend = False
kombineret.camera = {"azim": 37, "elev": 16}
kombineret.show()
Et tangentielt kurveintegral af \(\boldsymbol V\) langs en trappelinje \({\mathcal T}\) kan findes som summen af de tangentielle kurveintegraler langs hver af de tre linjestykker. Og her ser vi fordelen ved trappelinjemetoden; deres tangentvektorer er nemlig meget simple:
r1d = r1.diff(u)
r2d = r2.diff(u)
r3d = r3.diff(u)
r1d, r2d, r3d
hvilket gør de tre integrander særdeles simple:
Vi er dermed nået frem til følgende formel for det tangentielle kurveintegral af \(\pmb{V}\) langs en trappelinje til et vilkårligt punkt i \(\Bbb R^3\):
Gradientfelt eller ej?#
Vi ønsker at undersøge, hvorvidt følgende vektorfelt \(\pmb{V}\) er et gradientvektorfelt:
V = Matrix([y**2 + z, 2 * y * z**2 + 2 * y * x, 2 * y**2 * z + x])
V
Lad os finde det tangentielle kurveintegral af \(\pmb{V}\) langs trappelinjen til et vilkårligt punkt. Vi anvender formlen fra forrige afsnit og opdeler integrationen i tre bidder, hvis tre integrander bliver:
integrand1 = V[0].subs({x: u, y: 0, z: 0})
integrand2 = V[1].subs({y: u, z: 0})
integrand3 = V[2].subs({z: u})
integrand1, integrand2, integrand3
Det tangentielle kurveintegral bliver:
F = (integrate(integrand1,(u,0,x)) + integrate(integrand2,(u,0,y)) + integrate(integrand3,(u,0,z)))
F
Dette er en funktion i \(x,y,z\). Lad os finde dens gradient:
F_grad = dtutools.gradient(F)
F_grad, Eq(F_grad, V)
Da \(\pmb{V}\) er identisk med gradienten af \(F\), så er \(F\) en stamfunktion til \(\pmb{V}\), og \(\pmb{V}\) er et gradientvektorfelt!
Cirkulation i et gradientvektorfelt#
Betragt vektorfeltet \(\pmb{V}\) fra forrige afsnit samt følgende knude, parametriseret med \(t \in[-\pi,\pi]\):
t = symbols("t")
knude = (
Matrix([-10 * cos(t) - 2 * cos(5 * t) + 15 * sin(2 * t),
-15 * cos(2 * t) + 10 * sin(t) - 2 * sin(5 * t),
10 * cos(3 * t)])
*S(1)/10
)
knude
dtuplot.plot3d_parametric_line(*knude, (t, -pi, pi), rendering_kw={"color": "blue"}, legend=False,colorbar=False)
<spb.backends.matplotlib.matplotlib.MatplotlibBackend at 0x7fa52cd51e50>
En knude er en lukket kurve. Tangentielle kurveintegraler langs lukkede kurver kaldes også cirkulationer. Lad os beregne det tangentielle kurveintegral af \(\pmb{V}\) langs denne knude. Udkommentér følgende kodelinje, og kør den, når du er klar - vær tålmodig, da dette integral kan tage mere end et minut for Sympy at udregne:
#integrate(V.subs({x: knude[0], y: knude[1], z: knude[2]}).dot(knude.diff(t)), (t, -pi, pi))
Du burde få resultatet \(0\).
Det tangentielle kurveintegral af et gradientfelt er uafhængigt af ruten og afhænger dermed kun af endepunkterne, \(\boldsymbol a\) og \(\boldsymbol b\). Integralregningens fundamentalsætning fortæller ligefrem for gradientvektorfelter, at:
hvor \(F\) er en stamfunktion. Det er åbenlyst, at det tangentielle kurveintegral af et gradientvektorfelt langs en hvilken som helst lukket kurve altid vil være nul. Med andre ord, enhver cirkulation af et gradientvektorfelt er nul.
Integralkurver (flowkurver)#
Forestil dig, at du til tiden \(t=0\) slipper en partikel i et kraftvektorfelt i punktet \(\pmb{x}_0\). Hvordan vil denne partikel bevæge sig? Hvilken bane vil den følge? Banen vil være en kurve, hvis parameterfremstilling kan betegnes \(\pmb{r}(t)\), der kan fortolkes som positionen som funktion af tiden i et fysisk scenario. Et mere intuitivt billede kunne være en støvpartikel, der “flyver omkring” i vinden.
Sådanne kurver kaldes integralkurver eller nogle gange flowkurver. Bemærk, at det i de ovenstående fysiske analogier er vigtigt, at partiklen opfattes som masseløs, så inertieffekter ikke har nogen indflydelse - en flowkurve er den rute, en partikel vil følge, hvis den kun er under indflydelse af vektorfeltet.
Lærebogen fortæller, at flowkurver er løsninger til følgende differentialligningssystem:
hvor \(\pmb{x}_0\) er startpunktet.
Betragt følgende vektorfelt i \(\Bbb R^2\):
x,y = symbols('x y')
V = Matrix([-S(1)/4*x + S(1)/2*y,S(1)/2*x + S(1)/4*y])
V
Lad to partikler \(A\) og \(B\) starte i punkterne hhv. \(\boldsymbol s_A\) og \(\boldsymbol s_B\):
sA, sB = Matrix([5, 0]), Matrix([-3, S(1)/2])
Det differentialligningssystem, der nu skal løses, er:
hvor \(\boldsymbol r = (r_1,r_2)\). Anvendes begyndelsesværdibetingelsen \(\boldsymbol r(0)=\boldsymbol s_A=(5,0)\), så dannes flowkurven for partikel \(A\), mens \(\boldsymbol r(0)=\boldsymbol s_B=(-3,\frac12)\) danner flowkurven for \(B\).
Bemærk, at følgende tilgang til løsning af systemer af ordinære differentialligninger (eng: ordinary differential equations, ODEs) med Sympy blev behandlet i en Python-demo i kurset Matematik 1a. Har du brug for flere detaljer eller en langsommere gennemgang af metoden, vil vi referere dig dertil.
Vi definerer systemets matrix:
A = Matrix(2, 2, [S("-1/4"), S("1/2"), S("1/2"), S("1/4")])
og opstiller de ubekendte koordinatfunktioner som Sympy-funktioner, hvorefter de differentieres, så vi kan opstille ovenstående matrixligning:
r1 = Function('r1')
r2 = Function('r2')
r = Matrix([r1(t),r2(t)])
dr = diff(r,t)
ode_sys = dr - A * r
ode_sys
Vi løser systemet med dsolve-kommandoen fra dtutools (bemærk, at vi flyttede alt over på venstresiden i ode_sys = dr - A * r, da dsolve antager en nul-højreside):
dtutools.dsolve(ode_sys)
Dette udtryk beskriver de to koordinatfunktioner til enhver flowkurve. Vælges specifikke værdier til de ubekendte konstanter, så opnås én specifik flowkurve. Vi gør dette ved at tilføje den givne begyndelsesværdibetingelse med ics-argumentet:
rA_losn = dtutools.dsolve(ode_sys, ics = {r1(0):sA[0], r2(0):sA[1]})
rA_losn
rB_losn = dtutools.dsolve(ode_sys, ics = {r1(0):sB[0], r2(0):sB[1]})
rB_losn
Vi udtrækker parameterkurverne:
rA = Matrix([rA_losn[r1(t)], rA_losn[r2(t)]])
rB = Matrix([rB_losn[r1(t)], rB_losn[r2(t)]])
rA, rB
Et plot af de to kurver:
v_felt = dtuplot.plot_vector(A * Matrix([x, y]),n=10,scalar=False,colorbar=False,quiver_kw={"color": "black"},show=False)
rA_plot = dtuplot.plot_parametric(
*rA, [t, 0, 3], rendering_kw={"color": "red"}, colorbar=False, show=False
)
rB_plot = dtuplot.plot_parametric(
*rB, (t, 0, 4), rendering_kw={"color": "blue"}, colorbar=False, show=False
)
(v_felt + rA_plot + rB_plot).show()
No ranges were provided. This function will attempt to find them, however the order will be arbitrary, which means the visualization might be flipped.