diff --git a/book/0_overview/schedule.md b/book/0_overview/schedule.md index 7847f84..510e24e 100644 --- a/book/0_overview/schedule.md +++ b/book/0_overview/schedule.md @@ -4,57 +4,3 @@ Each unit runs over one week and consists of three lessons, numbered after the u [My Timetable](https://mytimetable.tudelft.nl/) carries the authoritative schedule, with rooms and any changes. -## Quarter 1 - -| Unit | Topic | Lesson | Date | Time | -| :--- | :--- | :--- | :--- | :--- | -| 1.1 | Gradient and divergence | 1.1.1 | Tue 1 Sep 2026 | 08:45-10:30 | -| | | 1.1.2 | Thu 3 Sep 2026 | 15:45-17:30 | -| | | 1.1.3 | Fri 4 Sep 2026 | 13:45-15:30 | -| 1.2 | Curl | 1.2.1 | Mon 7 Sep 2026 | 10:45-12:30 | -| | | 1.2.2 | Tue 8 Sep 2026 | 13:45-15:30 | -| | | 1.2.3 | Fri 11 Sep 2026 | 13:45-16:30 | -| 1.3 | Potential fields: history and experiments | 1.3.1 | Mon 14 Sep 2026 | 10:45-12:30 | -| | | 1.3.2 | Tue 15 Sep 2026 | 13:45-15:30 | -| | | 1.3.3 | Fri 18 Sep 2026 | 13:45-15:30 | -| 1.4 | Potential fields: gravity, magnetic field of the Earth | 1.4.1 | Mon 21 Sep 2026 | 10:45-12:30 | -| | | 1.4.2 | Tue 22 Sep 2026 | 13:45-15:30 | -| | | 1.4.3 | Fri 25 Sep 2026 | 13:45-16:30 | -| 1.5 | Electric field. Diffusion fields: hot wire | 1.5.1 | Mon 28 Sep 2026 | 10:45-12:30 | -| | | 1.5.2 | Tue 29 Sep 2026 | 13:45-15:30 | -| | | 1.5.3 | Fri 2 Oct 2026 | 13:45-15:30 | -| 1.6 | Diffusion fields: boundary conditions, heat in 2D and 3D | 1.6.1 | Mon 5 Oct 2026 | 10:45-12:30 | -| | | 1.6.2 | Tue 6 Oct 2026 | 15:45-17:30 | -| | | 1.6.3 | Fri 9 Oct 2026 | 13:45-16:30 | -| 1.7 | Mechanical waves: strings, acoustic waves, 2D and 3D | 1.7.1 | Mon 12 Oct 2026 | 10:45-12:30 | -| | | 1.7.2 | Tue 13 Oct 2026 | 13:45-15:30 | -| | | 1.7.3 | Fri 16 Oct 2026 | 13:45-15:30 | -| 1.8 | Mechanical waves: power flux | 1.8.1 | Mon 19 Oct 2026 | 10:45-12:30 | -| | | 1.8.2 | Tue 20 Oct 2026 | 13:45-15:30 | -| | | 1.8.3 | Fri 23 Oct 2026 | 13:45-16:30 | -| 1.9 | Unsupervised study | | | | -| 1.10 | Midterm week: exam and discussion of solutions | 1.10.1 | | | -| | | 1.10.2 | | | -| | | 1.10.3 | Fri 6 Nov 2026 | 13:30-16:30 | - -## Quarter 2 - -| Unit | Topic | Lesson | Date | Time | -| :--- | :--- | :--- | :--- | :--- | -| 2.1 | Electromagnetism: Maxwell's equations, plane waves, telegraph equation | 2.1.1 | Mon 9 Nov 2026 | 13:45-15:30 | -| | | 2.1.2 | Tue 10 Nov 2026 | 13:45-15:30 | -| | | 2.1.3 | Fri 13 Nov 2026 | 10:45-12:30 | -| 2.2 | 3D waves, Poynting vector, polarisation, lossy and lossless media | 2.2.1 | Mon 16 Nov 2026 | 13:45-15:30 | -| | | 2.2.2 | Tue 17 Nov 2026 | 13:45-15:30 | -| | | 2.2.3 | Fri 20 Nov 2026 | 09:45-12:30 | -| 2.3 | Reflection, transmission, refraction. Multi-layered media | 2.3.1 | Mon 23 Nov 2026 | 13:45-15:30 | -| | | 2.3.2 | Tue 24 Nov 2026 | 13:45-15:30 | -| | | 2.3.3 | Fri 27 Nov 2026 | 10:45-12:30 | -| 2.4 | Trapped and surface waves. Phase and group velocity | 2.4.1 | Mon 30 Nov 2026 | 13:45-15:30 | -| | | 2.4.2 | Tue 1 Dec 2026 | 08:45-10:30 | -| | | 2.4.3 | Fri 4 Dec 2026 | 09:45-12:30 | -| 2.8 | Unsupervised study | | | | -| 2.9 | Unsupervised study | | | | -| 2.10 | Resit exam | | Wed 27 Jan 2027 | 13:30-16:30 | - -The exam is on Wed 16 Dec 2026, 13:30-16:30. The longer practicals, running to 16:30, end with a formative assessment. diff --git a/book/1_gradient_divergence_curl/coord_sys.md b/book/1_gradient_divergence_curl/coord_sys.md index 4d3ccca..0caf67a 100644 --- a/book/1_gradient_divergence_curl/coord_sys.md +++ b/book/1_gradient_divergence_curl/coord_sys.md @@ -29,6 +29,18 @@ $$ \boldsymbol r = x\hat{\boldsymbol x} + y\hat{\boldsymbol y} + z\hat{\boldsymbol z}. $$ +Each base vector can be obtained by differentiating the position vector with respect to the corresponding coordinate, + +$$ +\hat{\boldsymbol x} = \partial_x\boldsymbol r, +\qquad +\hat{\boldsymbol y} = \partial_y\boldsymbol r, +\qquad +\hat{\boldsymbol z} = \partial_z\boldsymbol r. +$$ (eq:cartbase) + +We use this construction again below to find the base vectors of the cylindrical and spherical coordinate systems, where the derivatives do not come out with unit length and a normalisation factor is needed. + It is customary in the Earth Sciences to let the positive $\hat{\boldsymbol z}$-axis point downward, as depicted in {numref}`fig-cartframe`. ```{figure} figures/Cartframe.png @@ -66,7 +78,7 @@ $$ \boldsymbol r' = \hat{\boldsymbol e}_x(x-\lambda_x) + \hat{\boldsymbol e}_y(y-\lambda_y) + \hat{\boldsymbol e}_z(z-\lambda_z). $$ -Since distance should be invariant under rotation, only orthogonal tensors $\{\hat{\boldsymbol e}_x,\hat{\boldsymbol e}_y,\hat{\boldsymbol e}_z\}$ describe a rotation, and when these vectors have unit amplitude they span a base for the new frame of reference, in which case they are orthonormal vectors. +Since distance should be invariant under rotation, only orthogonal tensors $\{\hat{\boldsymbol e}_x,\hat{\boldsymbol e}_y,\hat{\boldsymbol e}_z\}$ describe a rotation, and when these vectors have unit amplitude they span a base for the new frame of reference, in which case they are orthonormal vectors, as shown in {numref}`fig-rotcartframe`. ```{figure} figures/rotCartframe.png :name: fig-rotcartframe @@ -114,6 +126,18 @@ $$ \hat{\boldsymbol x} = \hat{\boldsymbol y}\times\hat{\boldsymbol z}. $$ +You will also encounter triple vector products of the kind $\boldsymbol a\times(\boldsymbol b\times\boldsymbol c)$, which can be evaluated as + +$$ +\boldsymbol a\times(\boldsymbol b\times\boldsymbol c) = (\boldsymbol a\cdot\boldsymbol c)\boldsymbol b - (\boldsymbol a\cdot\boldsymbol b)\boldsymbol c . +$$ (eq:tripprod) + +The result lies in the plane spanned by $\boldsymbol b$ and $\boldsymbol c$, because $\boldsymbol b\times\boldsymbol c$ is perpendicular to that plane and the second cross product turns the result back into it. The order of the brackets matters, $\boldsymbol a\times(\boldsymbol b\times\boldsymbol c)\ne(\boldsymbol a\times\boldsymbol b)\times\boldsymbol c$. The following identity can be useful as well, + +$$ +\boldsymbol a\times(\boldsymbol b\times\boldsymbol c) + \boldsymbol b\times(\boldsymbol c\times\boldsymbol a) = (\boldsymbol a\times\boldsymbol b)\times\boldsymbol c . +$$ (eq:tripprod2) + ## Curvilinear coordinate systems Apart from the Cartesian reference frame, which is a rectangular coordinate system, two coordinate systems are often employed that use curved base vectors. One is the cylindrical coordinate system and the other is the spherical coordinate system. The point shown in {numref}`fig-cartframe` is depicted in cylindrical and spherical coordinate systems in {numref}`fig-cylsphere`. @@ -282,13 +306,26 @@ $$ ## Exercises 1. What is the length of the vector function $\boldsymbol v$? -2. Show that $\hat{\boldsymbol x} = \partial\boldsymbol r/\partial x$. -3. A two-dimensional rectangle in the plane $z=0$ is spanned by the two vectors $\boldsymbol d_x = d_x\hat{\boldsymbol x}$ and $\boldsymbol d_y = d_y\hat{\boldsymbol y}$, where $d_x$ and $d_y$ are the lengths in the $x$- and $y$-directions, respectively, and $\hat{\boldsymbol n}$ is the unit normal on the rectangle pointing in the positive $z$-direction. Give a geometrical interpretation of the product $\hat{\boldsymbol n}\cdot(\boldsymbol d_x\times\boldsymbol d_y)$. -4. A three-dimensional rectangle, a brick, with dimensions $d_x,d_y,d_z$ is spanned by the three vectors $\boldsymbol d_x = d_x\hat{\boldsymbol x}$, $\boldsymbol d_y = d_y\hat{\boldsymbol y}$ and $\boldsymbol d_z = d_z\hat{\boldsymbol z}$. Give a geometrical interpretation of the product $\boldsymbol d_x\cdot(\boldsymbol d_y\times\boldsymbol d_z)$. -5. Consider a smooth surface $\mathbb{S}$ with unique unit normal vector $\hat{\boldsymbol n}$. Show that any vector quantity $\boldsymbol H$ can be composed as $\boldsymbol H = (\hat{\boldsymbol n}\cdot\boldsymbol H)\hat{\boldsymbol n} + (\hat{\boldsymbol n}\times\boldsymbol H)\times\hat{\boldsymbol n}$ and give a geometric interpretation of the two terms. -6. A smooth surface $\mathbb{S}$ has a unique unit normal vector $\hat{\boldsymbol n}$. Decompose the gradient operator into a part tangential and a part normal to the surface $\mathbb{S}$. -7. Use the same reasoning as in the exercise above and find $\hat{\boldsymbol r} = A_r\,\partial\boldsymbol r/\partial r$, $\hat{\boldsymbol\phi} = A_\phi\,\partial\boldsymbol r/\partial\phi$, and $\hat{\boldsymbol\theta} = A_\theta\,\partial\boldsymbol r/\partial\theta$. Carry out the differentiations and find the coefficients $(A_r,A_\phi,A_\theta)$ by requiring that these vectors have unit length. These results should lead to an expression for the unit vectors of the spherical coordinate system in Cartesian coordinates. -8. The upper right-hand side of the matrix of {numref}`tab-direction-cosines` is left empty. The $3\times3$ block in the bottom-left corner of the table relates the unit vectors of the spherical reference frame to those of the Cartesian reference frame. Suppose we write this as +2. Show that $\boldsymbol a\cdot(\boldsymbol b\times\boldsymbol c) = \boldsymbol b\cdot(\boldsymbol c\times\boldsymbol a) = \boldsymbol c\cdot(\boldsymbol a\times\boldsymbol b)$. +3. Evaluate + + $$ + \begin{aligned} + \hat{\boldsymbol x}&\cdot(\hat{\boldsymbol y}\times\hat{\boldsymbol z}), &\qquad + \hat{\boldsymbol x}&\cdot(\hat{\boldsymbol z}\times\hat{\boldsymbol y}), \\ + \hat{\boldsymbol y}&\cdot(\hat{\boldsymbol x}\times\hat{\boldsymbol z}), &\qquad + \hat{\boldsymbol y}&\cdot(\hat{\boldsymbol z}\times\hat{\boldsymbol x}), \\ + \hat{\boldsymbol z}&\cdot(\hat{\boldsymbol y}\times\hat{\boldsymbol x}), &\qquad + \hat{\boldsymbol z}&\cdot(\hat{\boldsymbol x}\times\hat{\boldsymbol y}). + \end{aligned} + $$ +4. A two-dimensional rectangle in the plane $z=0$ is spanned by the two vectors $\boldsymbol d_x = d_x\hat{\boldsymbol x}$ and $\boldsymbol d_y = d_y\hat{\boldsymbol y}$, where $d_x$ and $d_y$ are the lengths in the $x$- and $y$-directions, respectively, and $\hat{\boldsymbol n}$ is the unit normal on the rectangle pointing in the positive $z$-direction. Give a geometrical interpretation of the product $\hat{\boldsymbol n}\cdot(\boldsymbol d_x\times\boldsymbol d_y)$. +5. A three-dimensional rectangle, a brick, with dimensions $d_x,d_y,d_z$ is spanned by the three vectors $\boldsymbol d_x = d_x\hat{\boldsymbol x}$, $\boldsymbol d_y = d_y\hat{\boldsymbol y}$ and $\boldsymbol d_z = d_z\hat{\boldsymbol z}$. Give a geometrical interpretation of the product $\boldsymbol d_x\cdot(\boldsymbol d_y\times\boldsymbol d_z)$. +6. Evaluate $(\boldsymbol a\times\boldsymbol b)\times\boldsymbol c$. +7. Consider a smooth surface $\mathbb{S}$ with unique unit normal vector $\hat{\boldsymbol n}$. Show that any vector quantity $\boldsymbol H$ can be composed as $\boldsymbol H = (\hat{\boldsymbol n}\cdot\boldsymbol H)\hat{\boldsymbol n} + (\hat{\boldsymbol n}\times\boldsymbol H)\times\hat{\boldsymbol n}$ and give a geometric interpretation of the two terms. +8. A smooth surface $\mathbb{S}$ has a unique unit normal vector $\hat{\boldsymbol n}$. Decompose the gradient operator into a part tangential and a part normal to the surface $\mathbb{S}$. +9. Find $\hat{\boldsymbol r} = A_r\,\partial\boldsymbol r/\partial r$, $\hat{\boldsymbol\phi} = A_\phi\,\partial\boldsymbol r/\partial\phi$, and $\hat{\boldsymbol\theta} = A_\theta\,\partial\boldsymbol r/\partial\theta$. Carry out the differentiations and find the coefficients $(A_r,A_\phi,A_\theta)$ by requiring that these vectors have unit length. These results should lead to an expression for the unit vectors of the spherical coordinate system in Cartesian coordinates. +10. The upper right-hand side of the matrix of {numref}`tab-direction-cosines` is left empty. The $3\times3$ block in the bottom-left corner of the table relates the unit vectors of the spherical reference frame to those of the Cartesian reference frame. Suppose we write this as $$ \left(\begin{array}{c} \hat{\boldsymbol r} \\ \hat{\boldsymbol\phi} \\ \hat{\boldsymbol\theta}\end{array}\right) @@ -301,7 +338,7 @@ $$ -\sin(\phi) & \cos(\phi) & 0 \\ \cos(\phi)\cos(\theta) & \sin(\phi)\cos(\theta) & -\sin(\theta) \end{array}\right). - $$ + $$ (eq:Rmat) Show that @@ -311,5 +348,16 @@ $$ $$ where $\mathsf{R}^{t}$ denotes the transpose of $\mathsf{R}$. Then show that $\mathsf{R}\mathsf{R}^{t} = \mathsf{I}$, where $\mathsf{I}$ is the $3\times3$ unit matrix, implying that the transpose of $\mathsf{R}$ is equal to its inverse. This follows from the fact that $\mathsf{R}$ is a matrix of orthonormal vectors and is therefore an orthonormal matrix. -9. Give explicit expressions for the base vectors of the spherical reference frame by carrying out the matrix-vector multiplication of {eq}`eq:sphCar`. Notice that all three base vectors depend on both angles. This implies that the base vectors are not constant but depend on position! The spherical reference frame is not an inertial frame. -10. Carry out the following differentiations: $\partial\hat{\boldsymbol r}/\partial\theta$, $\partial\hat{\boldsymbol\theta}/\partial\theta$, $\partial\hat{\boldsymbol\phi}/\partial\theta$ and $\partial\hat{\boldsymbol r}/\partial\phi$, $\partial\hat{\boldsymbol\theta}/\partial\phi$, $\partial\hat{\boldsymbol\phi}/\partial\phi$. +11. Give explicit expressions for the base vectors of the spherical reference frame by carrying out the matrix-vector multiplication of {eq}`eq:sphCar`, with the rotation matrix given by {eq}`eq:Rmat`. You should find that + + $$ + \hat{\boldsymbol r} = \left(\begin{array}{c} \cos(\phi)\sin(\theta) \\ \sin(\phi)\sin(\theta) \\ \cos(\theta)\end{array}\right), + \qquad + \hat{\boldsymbol\theta} = \left(\begin{array}{c} \cos(\phi)\cos(\theta) \\ \sin(\phi)\cos(\theta) \\ -\sin(\theta)\end{array}\right), + \qquad + \hat{\boldsymbol\phi} = \left(\begin{array}{c} -\sin(\phi) \\ \cos(\phi) \\ 0\end{array}\right). + $$ + + Notice that each base vector depends on at least one angle. This implies that the base vectors are not constant but depend on position! The spherical reference frame is not an inertial frame. +12. Evaluate $\hat{\boldsymbol r}\times\hat{\boldsymbol\phi}$, $\hat{\boldsymbol r}\times\hat{\boldsymbol\theta}$, and $\hat{\boldsymbol\phi}\times\hat{\boldsymbol\theta}$. +13. Carry out the following differentiations: $\partial\hat{\boldsymbol r}/\partial\theta$, $\partial\hat{\boldsymbol\theta}/\partial\theta$, $\partial\hat{\boldsymbol\phi}/\partial\theta$ and $\partial\hat{\boldsymbol r}/\partial\phi$, $\partial\hat{\boldsymbol\theta}/\partial\phi$, $\partial\hat{\boldsymbol\phi}/\partial\phi$, and express them all in terms of $\hat{\boldsymbol r}$, $\hat{\boldsymbol\theta}$ and $\hat{\boldsymbol\phi}$. diff --git a/book/1_gradient_divergence_curl/curl.md b/book/1_gradient_divergence_curl/curl.md index d73a939..e763c67 100644 --- a/book/1_gradient_divergence_curl/curl.md +++ b/book/1_gradient_divergence_curl/curl.md @@ -82,22 +82,112 @@ $$ \oint_{\boldsymbol r}\boldsymbol\tau\cdot\boldsymbol v\,\mathrm{d}l = \int_{\boldsymbol r\in\mathbb{S}}\hat{\boldsymbol n}\cdot(\nabla\times\boldsymbol v)\,\mathrm{d}S . $$ (eq:stokes) +## Vector identities with the curl + +The curl as expressed in {eq}`eq:curl` can be written as a matrix-vector operation, + +$$ +\nabla\times\boldsymbol v = \left(\begin{array}{ccc} +0 & -\partial_z & \partial_y \\ +\partial_z & 0 & -\partial_x \\ +-\partial_y & \partial_x & 0 +\end{array}\right)\left(\begin{array}{c} v_x \\ v_y \\ v_z\end{array}\right). +$$ (eq:curlmat) + +The matrix is antisymmetric and its diagonal is empty, which is another way of saying that no component of $\boldsymbol v$ contributes to the component of $\nabla\times\boldsymbol v$ along its own direction. + +The curl of a curl is given by + +$$ +\nabla\times\nabla\times\boldsymbol v = \nabla(\nabla\cdot\boldsymbol v) - \nabla^2\boldsymbol v, +$$ (eq:curlcurl) + +where $\nabla^2 = \nabla\cdot\nabla$ is the Laplacian. The curl of the curl of a vector field is the gradient of the divergence of that field, given by the first term on the right-hand side, minus the divergence of the gradient of that field, given by the second term. In this case the evaluation in terms of vector operations is the same as in {eq}`eq:tripprod`, with $\boldsymbol a$ and $\boldsymbol b$ both replaced by $\nabla$. + +If the curl is taken of a vector product of two vector functions, the product rule for differentiation must be taken into account as well, + +$$ +\nabla\times(\boldsymbol v\times\boldsymbol w) = \boldsymbol v(\nabla\cdot\boldsymbol w) - \boldsymbol w(\nabla\cdot\boldsymbol v) + (\boldsymbol w\cdot\nabla)\boldsymbol v - (\boldsymbol v\cdot\nabla)\boldsymbol w . +$$ (eq:curlvecprod) + +The first two terms take the divergence of $\boldsymbol w$ and of $\boldsymbol v$ and point the result along $\boldsymbol v$ and $-\boldsymbol w$ respectively, while the last two terms take the derivative of $\boldsymbol v$ and of $\boldsymbol w$ along the direction of $\boldsymbol w$ and $-\boldsymbol v$ respectively. + +The divergence operator can also act on the vector product of two functions, $\nabla\cdot(\boldsymbol v\times\boldsymbol w)$. This is evaluated with the vector rules of the exercises on coordinate systems, keeping the product rule for differentiation in mind, because the $\nabla$-operator acts on both $\boldsymbol v$ and $\boldsymbol w$. It is given by + +$$ +\nabla\cdot(\boldsymbol v\times\boldsymbol w) = \boldsymbol w\cdot(\nabla\times\boldsymbol v) - \boldsymbol v\cdot(\nabla\times\boldsymbol w). +$$ (eq:divvecprod) + +The divergence of a vector product of two functions takes the curl of each of them, computes the scalar product with the other, and subtracts the results. + +## The magnetic field around an infinite current carrying wire + +In the chapter on Potential Fields you will investigate this problem a bit deeper, but here we use it to illustrate that a field that circulates around another field does not have a non-zero curl everywhere, and that it can have zero divergence as well. Let us take an infinitely long current carrying wire along the vertical axis. That makes it a two-dimensional problem, because nothing is changing in the $z$-direction. In cylindrical coordinates the magnetic field is given by + +$$ +\boldsymbol H = \frac{I}{2\pi\varrho}\hat{\boldsymbol\phi}, +$$ (eq:HJcyl) + +which in Cartesian coordinates is written as + +$$ +\boldsymbol H = \frac{I}{2\pi\varrho^2}\left(-y\,\hat{\boldsymbol x} + x\,\hat{\boldsymbol y}\right). +$$ (eq:HJcart) + +The curl of this magnetic field has only a vertical component, as you can imagine from Ampère's law, because it states that $\nabla\times\boldsymbol H = \boldsymbol J$, with $\boldsymbol J$ the electric current density in the wire. We have to look only at the vertical component, because $\boldsymbol J$ has only a vertical component. We find + +$$ +\hat{\boldsymbol z}\cdot(\nabla\times\boldsymbol H) = \partial_x H_y - \partial_y H_x = \frac{I}{2\pi}\left(\partial_y\frac{y}{\varrho^2} + \partial_x\frac{x}{\varrho^2}\right) = 0, \qquad \text{for } \varrho>0 . +$$ + +We find that the magnetic field is curl-free everywhere outside the wire. The field rotates around the wire but it has zero curl. If we take the divergence of the magnetic field, we find + +$$ +\nabla\cdot\boldsymbol H = \partial_x H_x + \partial_y H_y = \frac{I}{2\pi}\left(-\partial_x\frac{y}{\varrho^2} + \partial_y\frac{x}{\varrho^2}\right) = 0, \qquad \text{for } \varrho>0 . +$$ + +We find that the magnetic field is divergence free as well, everywhere outside the wire. We investigate what happens at the wire. For that we take a planar circular area in the $(x,y)$-plane, as a cross-section that goes through the wire, but we do not specify the radius. We multiply Ampère's law with a unit vector in the vertical direction and integrate over the surface area $\mathbb{S}$ to find + +$$ +\int_{\mathbb{S}}\hat{\boldsymbol z}\cdot(\nabla\times\boldsymbol H)\,\mathrm{d}x\,\mathrm{d}y = \int_{\mathbb{S}}\hat{\boldsymbol z}\cdot\boldsymbol J\,\mathrm{d}x\,\mathrm{d}y . +$$ + +The right-hand side is identified as the current $I$ running in the wire, and we use Stokes' theorem on the left-hand side to arrive at + +$$ +\oint_{\partial\mathbb{S}}\boldsymbol\tau\cdot\boldsymbol H\,\mathrm{d}l . +$$ + +This is a line integral around the full circle, which is the boundary of the circular surface area that we started out with, and $\boldsymbol\tau$ is the unit tangent vector. In cylindrical coordinates, $\boldsymbol\tau\,\mathrm{d}l = \hat{\boldsymbol\phi}\,\varrho\,\mathrm{d}\phi$. Substituting this together with the expression of the magnetic field in {eq}`eq:HJcyl` in the above equation results in + +$$ +\oint_{\partial\mathbb{S}}\boldsymbol\tau\cdot\boldsymbol H\,\mathrm{d}l = \frac{I}{2\pi}\int_{\phi=0}^{2\pi}\mathrm{d}\phi = I, +$$ + +which is equal to the surface integral with the normal component of the current. In conclusion, the magnetic field has zero curl at any point outside the wire, but the line integral around any circle around the wire of the tangential component of the magnetic field is equal to the current flowing in the wire. This will come back when we discuss Potential Fields, and again when we discuss Electromagnetic Fields. + +## Sources of non-zero curl + +Rigid rotation and shear are two known causes for generating a field with non-zero curl. + ## Exercises 1. Use Stokes' theorem to evaluate $\oint_{\boldsymbol r}\boldsymbol\tau\,\mathrm{d}l$, where $\boldsymbol\tau$ is the unit tangent along the closed boundary of the area $\mathbb{S}$. The integration runs in the direction of circulation that forms a right-handed system with the unit normal vector on $\mathbb{S}$. -2. Show that when $\boldsymbol v(\boldsymbol r) = \boldsymbol a\,p(\boldsymbol r)$, where $\boldsymbol a$ is an arbitrary constant vector and $p(\boldsymbol r)$ is a continuously differentiable scalar function, Stokes' integral theorem gives +2. Use the matrix expression for the curl in {eq}`eq:curlmat` to find the matrix expression for the curl of the curl of $\boldsymbol v$, as expressed in vector form in {eq}`eq:curlcurl`. +3. Give a detailed derivation to show that {eq}`eq:divvecprod` is correct. +4. Show that when $\boldsymbol v(\boldsymbol r) = \boldsymbol a\,p(\boldsymbol r)$, where $\boldsymbol a$ is an arbitrary constant vector and $p(\boldsymbol r)$ is a continuously differentiable scalar function, Stokes' integral theorem gives $$ \oint_{\boldsymbol r}\boldsymbol\tau\,p\,\mathrm{d}l = \int_{\boldsymbol r\in\mathbb{S}}(\hat{\boldsymbol n}\times\nabla)p\,\mathrm{d}S, $$ which is Stokes' theorem for the gradient. -3. Show that when $\boldsymbol v(\boldsymbol r) = \boldsymbol a\times\boldsymbol w(\boldsymbol r)$, where $\boldsymbol a$ is an arbitrary constant vector and $\boldsymbol w(\boldsymbol r)$ is a continuously differentiable vector function, Stokes' integral theorem gives +5. Show that when $\boldsymbol v(\boldsymbol r) = \boldsymbol a\times\boldsymbol w(\boldsymbol r)$, where $\boldsymbol a$ is an arbitrary constant vector and $\boldsymbol w(\boldsymbol r)$ is a continuously differentiable vector function, Stokes' integral theorem gives $$ \oint_{\boldsymbol r}\boldsymbol\tau\times\boldsymbol w\,\mathrm{d}l = \int_{\boldsymbol r\in\mathbb{S}}(\hat{\boldsymbol n}\times\nabla)\times\boldsymbol w\,\mathrm{d}S . $$ -4. Ampère's law is given by $\nabla\times\boldsymbol H = \boldsymbol J$, which states that the electric current is equal to the curl of the magnetic field. Convert this to integral form using Stokes' theorem, by using a flat surface $\mathbb{S}$ and choosing a unit normal vector $\hat{\boldsymbol n}$ on $\mathbb{S}$. You should find +6. Ampère's law is given by $\nabla\times\boldsymbol H = \boldsymbol J$, which states that the electric current is equal to the curl of the magnetic field. Convert this to integral form using Stokes' theorem, by using a flat surface $\mathbb{S}$ and choosing a unit normal vector $\hat{\boldsymbol n}$ on $\mathbb{S}$. You should find $$ \oint_{\boldsymbol r}\boldsymbol H\cdot\boldsymbol\tau\,\mathrm{d}l = \int_{\boldsymbol r\in\mathbb{S}}\hat{\boldsymbol n}\cdot\boldsymbol J\,\mathrm{d}S . diff --git a/book/1_gradient_divergence_curl/divergence.md b/book/1_gradient_divergence_curl/divergence.md index 1e97bf2..035de39 100644 --- a/book/1_gradient_divergence_curl/divergence.md +++ b/book/1_gradient_divergence_curl/divergence.md @@ -55,6 +55,140 @@ We have just derived Gauss' integral theorem, or divergence theorem, and we foun The divergence of a vector field is the outward flux of the vector field per unit volume. ::: +### Gauss' theorem in one, two and three dimensions + +In one dimension the vector function can have only one component, say $v_x$, and it can depend on the spatial variable $x$ only. A finite volume in one dimension is a line segment, and its surface consists of the two end points of that segment. Let the line run from $x=x_b$ to $x=x_e$, from beginning to end. The divergence is $\nabla\cdot\boldsymbol v = \partial_x v_x$ and Gauss' theorem reads + +$$ +\int_{x_b}^{x_e}\partial_x v_x\,\mathrm{d}x = v_x(x_e) - v_x(x_b). +$$ (eq:gauss1d) + +You will recognise this as the fundamental theorem of calculus, stating that integration reverses differentiation. How do we know that it is the term $v_x(x_b)$ that should be given the minus sign? + +In two dimensions a vector field can have two components and depend on two spatial variables. Take the $(x,y)$-plane as our two-dimensional space. The vector field is written as $\boldsymbol v(x,y) = v_x(x,y)\hat{\boldsymbol x} + v_y(x,y)\hat{\boldsymbol y}$, and we evaluate the outward flow out of the rectangular domain $x_b0$ that is valid until the ball hits the ground again for the first time. + + (b) Determine the time $T_0$ at which the ball hits the ground and the maximum height $H$ the ball reaches the first time. + + Assume that every time the ball hits the ground there is some plastic deformation of the ball and the ball loses a fraction $\gamma$ of its energy at every bounce, such that at the $n^{\text{th}}$ bounce the velocity can be expressed as $v_n = \sqrt{1-\gamma}\,v_{n-1}$ for $n>0$. + + (c) The time it takes to complete the $n^{\text{th}}$ bounce, $T_n$, can be written in terms of $T_{n-1}$ as $T_n = \alpha T_{n-1}$, and in terms of $T_0$ as $T_n = \beta T_0$. Determine $\alpha$ and $\beta$. + + (d) Show that $T_n = (1-\gamma)^{n/2}\sqrt{\dfrac{8H}{g}}$. + + (e) Give an expression for $T_\infty$ by evaluating the series $T_\infty = \sum_{m=0}^{\infty}T_m$. Since $\gamma$ is a fraction, it has a positive non-zero value smaller than 1, so that the series can be summed to an explicit expression. Why does it take only a finite time for the ball to make infinitely many bounces? + + (f) If the energy loss per bounce is extremely small, $\gamma\ll 1$, use a Taylor series expansion around $\gamma=0$ for $T_\infty$ and keep only the leading term as a first-order approximation to the time required to make an infinite number of bounces. + + (g) Plot the height as a function of time and try different values for $\gamma$, to understand truncation of a series as an approximation of a function. How many terms do you need in the sum to arrive at the same time as the approximate expression? + + :::{admonition} Answers to (a)–(f) + :class: tip dropdown + (a) $z = v_0 t - \tfrac{1}{2}gt^2$. + + (b) $H = \dfrac{v_0^2}{2g}$ and $T_0 = \dfrac{2v_0}{g}$. + + (c) $T_n$ is proportional to $v_n$, hence $T_n = \sqrt{1-\gamma}\,T_{n-1} = (1-\gamma)^{n/2}T_0$, so $\alpha=\sqrt{1-\gamma}$ and $\beta=(1-\gamma)^{n/2}$. + + (d) In the expression for $T_n$ in (c), express $T_0$ in terms of $H$ instead of in terms of $v_0$. + + (e) $T_\infty = T_0\sum_{m=0}^{\infty}(1-\gamma)^{m/2} = \sqrt{\dfrac{8H}{g}}\dfrac{1}{1-\sqrt{1-\gamma}}$. + + (f) In that case $\sqrt{1-\gamma}\approx 1-\tfrac{\gamma}{2}$ and $T_\infty \approx \sqrt{\dfrac{8H}{g}}\dfrac{2}{\gamma}$. + ::: diff --git a/book/2_potential_fields/.DS_Store b/book/2_potential_fields/.DS_Store index a015d6d..072a02b 100644 Binary files a/book/2_potential_fields/.DS_Store and b/book/2_potential_fields/.DS_Store differ diff --git a/book/2_potential_fields/labs/week4/current_loop_lab.html b/book/2_potential_fields/labs/week4/current_loop_lab.html new file mode 100644 index 0000000..251b363 --- /dev/null +++ b/book/2_potential_fields/labs/week4/current_loop_lab.html @@ -0,0 +1,297 @@ + + + + + + + + +
+
+
+
+
+
+
+
Field lines in the x–z plane: exact loop (solid) and dipole with the same moment (dashed)
+
+
+
|B| on the axis (log–log)
+
+
Dipole formula / exact field on the axis
+
+
+
+

+

The loop lies in the x–y plane and is seen edge-on: ⊗ current into the page, ⊙ current out of the page, so m = IπRL2 ẑ points up. Lengths in the upper panel are in units of RL. Exact axial field: B = μ0IRL2 / [2(RL2+z2)3/2]. Dipole formula on the axis: B = μ0m / (2πz3).

+ + + diff --git a/book/2_potential_fields/labs/week4/earth_dipole_lab.html b/book/2_potential_fields/labs/week4/earth_dipole_lab.html new file mode 100644 index 0000000..bf4fc8a --- /dev/null +++ b/book/2_potential_fields/labs/week4/earth_dipole_lab.html @@ -0,0 +1,251 @@ + + + + + + + + +
+
+
+
+
+ + +
+
+
Dipole field lines and the head-to-tail construction at the probe
+
+
+
|B| along the radial line through the probe
+
+
At the surface: angle below horizontal and |B|/B*
+
+
+
+

+

Drawn as in the lecture slides: m̂ = ẑ points up the page and θ is measured from m̂. For the present Earth, m̂ points to the southern end of the dipole axis, so the southern end (θ = 0) is at the top and the northern end (θ = 180°) at the bottom. Arrows at the probe show the bracket 3(m̂·r̂)r̂ − m̂ (blue: 3(m̂·r̂)r̂, red: −m̂, black: sum); their length does not depend on r. The field itself is B = B*(a/r)3 times this bracket, with B* = 29.7 µT and a = 6371 km.

+ + + diff --git a/book/2_potential_fields/labs/week4/fair_weather_lab.html b/book/2_potential_fields/labs/week4/fair_weather_lab.html new file mode 100644 index 0000000..742a40f --- /dev/null +++ b/book/2_potential_fields/labs/week4/fair_weather_lab.html @@ -0,0 +1,280 @@ + + + + + + + + +
+
+
+
+
+
+
+ + + +
+
+
Field strength |E|/E0, equipotentials (white), field lines (grey)
+
+
Profile along the vertical line through the test charge
+
+
+

+

Equipotentials are drawn every E0·1 m. The arrow on the test charge is the force F = qE, its length proportional to |F|. The grounded hemisphere (a > 0) is a crude model of a person, a tree or a small hill.

+ + + diff --git a/book/2_potential_fields/labs/week4/figures/earth_dipole_setup.png b/book/2_potential_fields/labs/week4/figures/earth_dipole_setup.png new file mode 100644 index 0000000..99224ad Binary files /dev/null and b/book/2_potential_fields/labs/week4/figures/earth_dipole_setup.png differ diff --git a/book/2_potential_fields/labs/week4/figures/earth_dipole_vectors_solution.png b/book/2_potential_fields/labs/week4/figures/earth_dipole_vectors_solution.png new file mode 100644 index 0000000..d8b61f8 Binary files /dev/null and b/book/2_potential_fields/labs/week4/figures/earth_dipole_vectors_solution.png differ diff --git a/book/2_potential_fields/labs/week4/figures/simple_ionosphere.png b/book/2_potential_fields/labs/week4/figures/simple_ionosphere.png new file mode 100644 index 0000000..85559b3 Binary files /dev/null and b/book/2_potential_fields/labs/week4/figures/simple_ionosphere.png differ diff --git a/book/2_potential_fields/labs/week4/figures/spherical_capacitor.png b/book/2_potential_fields/labs/week4/figures/spherical_capacitor.png new file mode 100644 index 0000000..ebd5868 Binary files /dev/null and b/book/2_potential_fields/labs/week4/figures/spherical_capacitor.png differ diff --git a/book/2_potential_fields/labs/week4/spherical_capacitor.py b/book/2_potential_fields/labs/week4/spherical_capacitor.py new file mode 100644 index 0000000..498d323 --- /dev/null +++ b/book/2_potential_fields/labs/week4/spherical_capacitor.py @@ -0,0 +1,66 @@ +"""Simple model of a spherical capacitor: V(r) = A + B/r between the shells. + +Boundary conditions: V(r_inner) = 0 and V(r_outer) = V_outer (user-set). +""" + +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np + +FIGURE_DIR = Path(__file__).parent / "figures" +FIGURE_DIR.mkdir(exist_ok=True) + + +def solve_coefficients(r_inner, r_outer, v_outer): + """Solve for A, B given V(r_inner) = 0 and V(r_outer) = v_outer.""" + b = v_outer / (1.0 / r_outer - 1.0 / r_inner) + a = -b / r_inner + return a, b + + +def potential(r, r_inner, r_outer, v_outer): + """Return V(r): 0 inside the inner shell, A + B/r between, v_outer beyond.""" + a, b = solve_coefficients(r_inner, r_outer, v_outer) + v = np.full_like(r, v_outer, dtype=float) + between = (r >= r_inner) & (r <= r_outer) + v[between] = a + b / r[between] + v[r < r_inner] = 0.0 + return v + + +def electric_field(r, r_inner, r_outer, v_outer): + """Return E(r) = -dV/dr = B / r**2 between the shells, else zero.""" + _, b = solve_coefficients(r_inner, r_outer, v_outer) + e = np.zeros_like(r, dtype=float) + between = (r >= r_inner) & (r <= r_outer) + e[between] = b / r[between] ** 2 + return e + + +def plot_spherical_capacitor(r_inner=1.0, r_outer=2.5, v_outer=10.0): + r = np.linspace(0.01, 1.5 * r_outer, 500) + v = potential(r, r_inner, r_outer, v_outer) + e = electric_field(r, r_inner, r_outer, v_outer) + + fig, (ax_v, ax_e) = plt.subplots(2, 1, figsize=(7.5, 7.5), sharex=True, layout="constrained") + + ax_v.plot(r, v, color="#2764ae") + ax_v.axvline(r_inner, color="0.6", linestyle="--", linewidth=1) + ax_v.axvline(r_outer, color="0.6", linestyle="--", linewidth=1) + ax_v.set_ylabel("$V(r)$") + ax_v.set_title("Spherical capacitor: potential and field between shells") + + ax_e.plot(r, e, color="#c43c39") + ax_e.axvline(r_inner, color="0.6", linestyle="--", linewidth=1) + ax_e.axvline(r_outer, color="0.6", linestyle="--", linewidth=1) + ax_e.set_xlabel("$r$") + ax_e.set_ylabel("$E(r)$") + + fig.savefig(FIGURE_DIR / "spherical_capacitor.png", dpi=220, bbox_inches="tight") + plt.close(fig) + + +if __name__ == "__main__": + plot_spherical_capacitor() + diff --git a/book/2_potential_fields/labs/week4/spherical_capacitor_lab.html b/book/2_potential_fields/labs/week4/spherical_capacitor_lab.html new file mode 100644 index 0000000..80f52f8 --- /dev/null +++ b/book/2_potential_fields/labs/week4/spherical_capacitor_lab.html @@ -0,0 +1,188 @@ + + + + + + + + +
+
+
+
+
+ +
+
Potential V(r) (kV)
+
Field E(r) = −dV/dr (V/m)
+
+

+ + + diff --git a/book/2_potential_fields/labs/week4/week4_exercises.md b/book/2_potential_fields/labs/week4/week4_exercises.md new file mode 100644 index 0000000..8a555ad --- /dev/null +++ b/book/2_potential_fields/labs/week4/week4_exercises.md @@ -0,0 +1,389 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Lab 4: Electrostatic and Magnetic Fields + +## 1. Explore a spherical capacitor + +Two concentric conducting shells with free space between them, an **inner shell** of radius $R_E=6370\ \text{km}$ (the Earth) held at $V=0$, and an **outer shell** of radius $R_I$ (the ionosphere) held at $V=V_o$, is the same setup as the Earth-ionosphere model in the {doc}`week 4 quiz `. Between the shells, the potential takes the form + +```{math} +V(r) = A + \frac{B}{r}, \qquad R_E \le r \le R_I, +``` + +with $A$ and $B$ fixed entirely by the two boundary conditions $V(R_E)=0$ and $V(R_I)=V_o$. Inside the inner shell $V=0$ (it is a conductor), and outside the outer shell $V=V_o$ with $\vec E = 0$ (the shells enclose zero net charge together). + +Use the sliders below to change the outer radius $R_I$ (km) and the outer voltage $V_o$ (kV, 0 to 200), and watch $V(r)$ and $E(r)=-dV/dr$ update. **The radial axis in the plots is not to scale**: the gap between the shells (tens to thousands of km) is stretched for readability against Earth's 6370 km radius. + +```{code-cell} ipython3 +:tags: [remove-input, remove-output] + +import numpy as np + +def solve_coefficients(r_inner, r_outer, v_outer): + """Solve A, B given V(r_inner) = 0 and V(r_outer) = v_outer.""" + b = v_outer / (1.0 / r_outer - 1.0 / r_inner) + a = -b / r_inner + return a, b + +def potential(r, r_inner, r_outer, v_outer): + a, b = solve_coefficients(r_inner, r_outer, v_outer) + r = np.asarray(r, float) + v = np.full_like(r, v_outer, dtype=float) + between = (r >= r_inner) & (r <= r_outer) + v[between] = a + b / r[between] + v[r < r_inner] = 0.0 + return v + +def field(r, r_inner, r_outer, v_outer): + """E(r) = -dV/dr = B / r**2 between the shells, else zero.""" + _, b = solve_coefficients(r_inner, r_outer, v_outer) + r = np.asarray(r, float) + e = np.zeros_like(r, dtype=float) + between = (r >= r_inner) & (r <= r_outer) + e[between] = b / r[between] ** 2 + return e + +# Boundary conditions and the field-potential relation, checked at an example (r_i, r_o, V_o). +r_i, r_o, v_o = 6370.0, 6470.0, 1.0e5 +np.testing.assert_allclose(potential(r_i, r_i, r_o, v_o), 0.0, atol=1e-9) +np.testing.assert_allclose(potential(r_o, r_i, r_o, v_o), v_o) +r_mid = 0.5 * (r_i + r_o) +eps = 1e-3 +numeric_e = -(potential(r_mid + eps, r_i, r_o, v_o) - potential(r_mid - eps, r_i, r_o, v_o)) / (2 * eps) +np.testing.assert_allclose(numeric_e, field(r_mid, r_i, r_o, v_o), rtol=1e-6) +print("Boundary conditions and E = -dV/dr checks passed.") +``` + +```{code-cell} ipython3 +:tags: [remove-input] + +# The HTML contains all controls and drawing code, with no external dependencies. +# An iframe keeps the explorer independent of the page styles. +import html as html_module +from pathlib import Path +from IPython.display import display + +for _candidate in ( + Path("spherical_capacitor_lab.html"), + Path("book/2_potential_fields/labs/week4/spherical_capacitor_lab.html"), +): + if _candidate.exists(): + explorer_html = _candidate.read_text() + break +else: + from pyodide.http import pyfetch + _r = await pyfetch("spherical_capacitor_lab.html") + explorer_html = (await _r.bytes()).decode() + +display({"text/html": ''}, raw=True) +``` + +### Explore, predict, explain + +1. **Reproduce the quiz numbers.** Set $R_I = 6470$ km (100 km altitude) and $V_o = 100$ kV, matching the week 4 quiz. Read off $A$ and $B$, and compare them to the closed-form expressions you derived by hand. Then check the field at 50 km altitude (probe $r=6420$ km) against your answer to part (e). +2. **Move the outer shell farther away.** Keep $V_o$ fixed and increase $R_I$. Does $|B|$ grow or shrink? Explain why the field between the shells changes even though $V_o$ has not. +3. **Increase $V_o$ toward 200 kV.** What happens to the field magnitude at a fixed altitude? Is the relationship linear? +4. **Move the probe outside $R_I$ and inside $R_E$.** Confirm that $V$ is constant and $E=0$ in both regions, consistent with each shell being an equipotential conductor. + +## 2. Charges in the fair-weather field + +On a clear day, the air above flat, open ground carries a downward electric field (W4L1, slides 16–17): +```{math} +\vec{E} \approx -E_0\,\hat{z}, \qquad E_0 \approx 100\ \mathrm{V/m}, \qquad V(z) = E_0 z \quad \text{with } V(0) = 0. +``` +Cosmic rays continuously ionise the air, producing free electrons and positive ions such as $\mathrm{N_2^+}$. Wind also lifts charged mineral dust from deserts into the atmosphere. Use $e = 1.602\cdot 10^{-19}\ \mathrm{C}$, $g = 9.81\ \mathrm{m/s^2}$ and $1\ \mathrm{eV} = 1.602\cdot 10^{-19}\ \mathrm{J}$ (the energy an elementary charge gains across $1\ \mathrm{V}$). + +Parts (a)–(d) of this exercise are question 2 of the {doc}`week 4 quiz `. Work through them first; the Python cell and the explorer below let you check those answers and extend them to part (e). + +(e) In the undisturbed fair-weather field, the potential difference between $z=0$ and $z=2\ \mathrm{m}$ is $200\ \mathrm{V}$ (quiz part (a)). You are standing on the ground and are about $2\ \mathrm{m}$ tall. Is there a $200\ \mathrm{V}$ potential difference between your head and your feet? Sketch how the equipotentials change around you and explain your reasoning. *Hint:* you are a conductor connected to the ground (W4L1, slide 14). + +### Check your answers with Python + +Fill in the blanks (`___`) and run the cell to check your numbers for parts (a), (b) and (d) of the quiz. + +```{code-cell} ipython3 +:tags: [skip-execution] + +import numpy as np + +e = 1.602e-19 # elementary charge [C] +E0 = 100.0 # fair-weather field strength [V/m] +g = 9.81 # gravitational acceleration [m/s^2] + +def V_fair(z): + """Fair-weather potential above flat ground, V(0) = 0.""" + return ___ + +# (b), (c): move each particle from z = 0 to z = 10 m +dV = V_fair(10.0) - V_fair(0.0) +for name, q in [("electron", -e), ("N2+ ion ", +e)]: + dU = ___ # change in potential energy [J] + W = ___ # work done by the field [J] + Fz = ___ # z-component of F = qE, with E = -E0 z_hat [N] + print(f"{name}: dV = {dV:.0f} V, dU = {dU:+.2e} J = {dU/e:+.0f} eV, " + f"W_field = {W:+.2e} J, F_z = {Fz:+.1e} N") + +# (d): dust grain levitated by the fair-weather field +a_d, rho_d = 1e-6, 2650.0 # radius [m], density [kg/m^3] +m_d = ___ # mass of the grain [kg] +q_d = ___ # charge magnitude for |qE| = mg [C] +print(f"m = {m_d:.2e} kg, |q| = {q_d:.2e} C = {q_d/e:.0f} excess electrons") + +# self-check +assert np.isclose(V_fair(2.0), 200.0), "V(2 m) should be 200 V" +assert np.isclose(q_d / e, 6.8e3, rtol=0.02), "check the mass or the force balance" +print("Self-check passed.") +``` + +The explorer below shows the fair-weather field over flat ground. You can add a grounded conducting hemisphere of radius $a$, a crude model of a person, a tree or a small hill. Its potential is +```{math} +V(\vec{r}) = E_0 z\left(1 - \frac{a^3}{r^3}\right), \qquad z \geq 0,\ r \geq a. +``` +The upper panel shows the field strength $|\vec{E}|/E_0$ in colour, the equipotentials in white (every $E_0\cdot 1\ \mathrm{m}$), the field lines in grey, and the force $\vec{F} = q\vec{E}$ on the test charge as an arrow. The lower panel shows $V(z)$ and $U(z)/e$ along the vertical line through the test charge. + +1. With $a = 0$, move the test charge up and down. Check your answers to quiz parts (a) and (b). +2. Switch between the electron and the ion. Which quantities change, and which stay the same? (W4L1, slide 9) +3. Set $a = 1\ \mathrm{m}$. Where do the equipotentials crowd together? Read $|\vec{E}|$ just above the top of the object and near its base. Use this to check your sketch for (e). + +```{code-cell} ipython3 +:tags: [remove-input] + +# The HTML contains all controls and drawing code, with no external dependencies. +# An iframe keeps the explorer independent of the page styles. +import html as html_module +from pathlib import Path +from IPython.display import display + +for _candidate in ( + Path("fair_weather_lab.html"), + Path("book/2_potential_fields/labs/week4/fair_weather_lab.html"), +): + if _candidate.exists(): + explorer_html = _candidate.read_text() + break +else: + from pyodide.http import pyfetch + _r = await pyfetch("fair_weather_lab.html") + explorer_html = (await _r.bytes()).decode() + +display({"text/html": ''}, raw=True) +``` + + +## 3. Explore Earth's dipole field + +Far from a compact current system, its magnetic field is that of a dipole (W4L2, slides 14–15). Earth's main field is modelled as a dipole at Earth's centre. As in the lecture, let $\hat m=\hat z$, let $\theta$ be the angle measured from $\hat m$, and work in the $x$–$z$ plane with $\hat r=\sin\theta\,\hat x+\cos\theta\,\hat z$ (slide 22). The field is +```{math} +\vec B = B_*\left(\frac{R}{r}\right)^3\left[3(\hat m\cdot\hat r)\,\hat r-\hat m\right], +\qquad B_*=\frac{\mu_0|\vec m|}{4\pi R^3}. +``` +For Earth, take $R=a=6371\ \mathrm{km}$ and $B_*\approx 29.7\ \mu\mathrm{T}$ (called $B_0$ in the teachbook section *Earth as a Magnetic Dipole*). For the present polarity, $\hat m$ points toward the **southern** end of the dipole axis: $\theta=0$ is the southern end, $\theta=\pi$ the northern end, and $\theta=\pi/2$ the dipole equator. + +Parts (a)–(d) of this exercise are question 3 of the {doc}`week 4 quiz `. Work through them first; the Python cell and the explorer below let you check those answers and extend them to part (e). + +(e) The quiz quotes the component form of the dipole field; here you derive it. Repeat part (b) of the quiz for a general $\theta$ at $r=a$. +1. Write $\hat z=\cos\theta\,\hat r-\sin\theta\,\hat\theta$, with $\hat\theta=\cos\theta\,\hat x-\sin\theta\,\hat z$ pointing along the ground toward the northern end of the axis. Show that the field has a radial component $B_r=2B_*\cos\theta$ and a horizontal component $B_\theta=B_*\sin\theta$. +2. Use the dipole latitude $\lambda_m=\theta-\pi/2$ (positive in the northern hemisphere) to show that the angle $I$ below the horizontal satisfies $\tan I=2\tan\lambda_m$. Check it against quiz part (b). +3. A navigator measures $I=70^\circ$. What is the dipole latitude? Near which latitudes does a small error in $I$ matter least? +### Check your answers with Python + +Fill in the blanks (`___`) and run the cell to check your numbers for parts (a)–(d) of the quiz and part (e). + +```{code-cell} ipython3 +:tags: [skip-execution] + +import numpy as np + +B_star = 29.7e-6 # B_* for Earth [T] +a = 6371e3 # R = a, Earth's reference radius [m] +m_hat = np.array([0.0, 1.0]) # (x, z): m_hat = z_hat, toward the SOUTHERN end of the axis + +def B_dipole(theta, r): + """Dipole field (Bx, Bz) [T] at polar angle theta (from m_hat) and distance r [m].""" + r_hat = np.array([np.sin(theta), np.cos(theta)]) + return ___ # B_* (a/r)^3 [3 (m.r) r - m] + +def below_horizontal(theta, r): + """Angle [deg] between B and the local horizontal, positive when B points into the ground.""" + r_hat = np.array([np.sin(theta), np.cos(theta)]) + B = B_dipole(theta, r) + B_radial = ___ # component of B along r_hat (positive = out of the ground) + return np.degrees(np.arcsin(-B_radial / np.linalg.norm(B))) + +# (a), (b): at the surface +for name, th in [("southern end", 0.0), ("dipole equator", np.pi/2), + ("northern end", np.pi), ("45 deg N", 3*np.pi/4)]: + B = B_dipole(th, a) + Bx, Bz = np.round(B / B_star, 2) + 0.0 # + 0.0 avoids printing -0.00 + I = round(below_horizontal(th, a), 1) + 0.0 + print(f"{name:15s} B/B* = ({Bx:+.2f}, {Bz:+.2f}), " + f"|B| = {np.linalg.norm(B)*1e6:5.1f} uT, below horizontal = {I:+6.1f} deg") + +# (c): Swarm at 450 km altitude above 45 deg N +r_swarm = ___ +print(f"(c) |B| at Swarm altitude = {np.linalg.norm(B_dipole(3*np.pi/4, r_swarm))*1e6:.1f} uT," + f" below horizontal = {below_horizontal(3*np.pi/4, r_swarm):.1f} deg") + +# (d): distance at which the field has dropped to 1% of its surface value +r_1pct = ___ +print(f"(d) r = {r_1pct/a:.2f} a = {r_1pct/1e3:.0f} km") + +# (e): dipole latitude for a measured angle I = 70 deg, from tan I = 2 tan(lambda_m) +lam_nav = ___ # [rad] +print(f"(e) I = 70 deg -> lambda_m = {np.degrees(lam_nav):.1f} deg N") + +# self-check +assert np.isclose(np.linalg.norm(B_dipole(np.pi/2, a)), B_star) +assert np.isclose(np.linalg.norm(B_dipole(3*np.pi/4, a)), 47.0e-6, rtol=1e-3) +assert np.isclose(below_horizontal(3*np.pi/4, a), 63.43, atol=0.01) +assert np.isclose(np.linalg.norm(B_dipole(3*np.pi/4, r_swarm)), 38.3e-6, rtol=2e-3) +assert np.isclose(np.linalg.norm(B_dipole(np.pi, r_1pct)) / np.linalg.norm(B_dipole(np.pi, a)), 0.01) +assert np.isclose(np.degrees(lam_nav), 53.95, atol=0.01) +print("Self-check passed.") +``` + +The explorer below draws the dipole field lines in the $x$–$z$ plane, oriented as in the lecture ($\hat m=\hat z$ up the page, so the southern end of Earth's axis is at the top). Choose a probe point with $\theta$ and $r/a$. At the probe, the blue, red and black arrows show the head-to-tail construction of the bracket $3(\hat m\cdot\hat r)\hat r-\hat m$. The dashed line is the local horizontal. The lower-left panel shows $|\vec B|$ along the radial line through the probe on log–log axes. The lower-right panel shows the angle below the horizontal and $|\vec B|/B_*$ at the surface as functions of $\theta$. + +1. At $r/a=1$, set $\theta=0^\circ$, $90^\circ$ and $135^\circ$ to check your answers to quiz parts (a) and (b), then $180^\circ$ to see the northern end. +2. Press *Swarm altitude*. Which numbers change, and which stay the same? Do the arrows at the probe change? (W4L2, slide 15) +3. In the lower-left panel, why is the curve a straight line? Read off where it crosses the $1\%$ line and compare with quiz part (d). By what factor does $|\vec B|$ drop between $r/a=1$ and $2$? (W4L2, slide 18) +4. In the lower-right panel, where is the field vertical, where is it horizontal, and where is $|\vec B|$ largest and smallest? Where does the angle change fastest with $\theta$? Relate this to part (e). +```{code-cell} ipython3 +:tags: [remove-input] + +# The HTML contains all controls and drawing code, with no external dependencies. +# An iframe keeps the explorer independent of the page styles. +import html as html_module +from pathlib import Path +from IPython.display import display + +for _candidate in ( + Path("earth_dipole_lab.html"), + Path("book/2_potential_fields/labs/week4/earth_dipole_lab.html"), +): + if _candidate.exists(): + explorer_html = _candidate.read_text() + break +else: + from pyodide.http import pyfetch + _r = await pyfetch("earth_dipole_lab.html") + explorer_html = (await _r.bytes()).decode() + +display({"text/html": ''}, raw=True) +``` + + +## 4. Explore a current loop and its dipole field + +Far from a compact current loop, its magnetic field is that of a dipole (W4L2, slide 14). A circular loop carrying current $I$ around an area $A$ has the magnetic moment +```{math} +\vec m = IA\,\hat n, +``` +where $\hat n$ is the normal to the loop given by the right-hand rule: curl the fingers along the current, and the thumb gives $\hat n$. Use $\mu_0 = 4\pi\cdot10^{-7}\ \mathrm{T\,m/A}$. + +Parts (a)–(d) of this exercise are question 4 of the {doc}`week 4 quiz `. Work through them first; the Python cell and the explorer below let you check those answers and extend them to part (e). + +(e) Return to the core loop of quiz part (b). An observer stands on Earth's surface above the northern end of the axis, at distance $z = a$ from the centre of the loop. How large is the error of the dipole formula there? How far from Earth's centre, in units of $a$, would the observer have to be for the dipole formula to be accurate to within $10\%$? What does this tell you about the single-loop picture of the geodynamo? + +### Check your answers with Python + +Fill in the blanks (`___`) and run the cell to check your numbers for parts (a)–(d) of the quiz and part (e). The last blank, `z_10`, is the height where the dipole formula becomes accurate to within $10\%$; compare it with explorer question 4. + +```{code-cell} ipython3 +:tags: [skip-execution] + +import numpy as np + +mu0 = 4e-7 * np.pi # [T m/A] +a, B_star, R_c = 6371e3, 29.7e-6, 3480e3 # Earth radius [m], B_* [T], outer-core radius [m] + +# (a), (b): Earth's moment and the equivalent core current +m_earth = ___ # from B_* = mu0 m / (4 pi a^3) [A m^2] +I_core = ___ # from m = I * pi R_c^2 [A] +print(f"(a) m = {m_earth:.2e} A m^2 (b) I = {I_core:.2e} A") + +def B_loop_axis(z, I, R): + """Exact field on the axis of a circular loop of radius R [T].""" + return mu0 * I * R**2 / (2 * (R**2 + z**2)**1.5) + +def B_dip_axis(z, m): + """Dipole formula on the axis [T].""" + return ___ + +# (c), (d): the survey loop +R_L, I_L = 50.0, 10.0 +m_L = ___ # moment of the survey loop [A m^2] +print(f"(c) m = {m_L:.3g} A m^2") +for z in (100.0, 250.0): # (d): z = 2 R_L and z = 5 R_L + B_ex, B_dp = B_loop_axis(z, I_L, R_L), B_dip_axis(z, m_L) + print(f"(d) at z = {z:.0f} m: exact {B_ex*1e9:.2f} nT, dipole {B_dp*1e9:.2f} nT, " + f"ratio {B_dp/B_ex:.2f}") +z_10 = ___ # height where B_dip / B_loop = 1.1 [m] +print(f" dipole formula within 10% beyond z = {z_10:.0f} m = {z_10/R_L:.1f} R_L") + +# (e): the core loop seen from Earth's surface on the axis +ratio_core = B_dip_axis(a, m_earth) / B_loop_axis(a, I_core, R_c) +print(f"(e) z/R_c = {a/R_c:.2f}: dipole / exact = {ratio_core:.2f}; " + f"10% needs r = {z_10/R_L * R_c / a:.2f} a") + +# self-check +assert np.isclose(m_earth, 7.68e22, rtol=2e-3) and np.isclose(I_core, 2.02e9, rtol=5e-3) +assert np.isclose(m_L, 7.854e4, rtol=1e-3) +assert np.isclose(B_dip_axis(100.0, m_L) / B_loop_axis(100.0, I_L, R_L), 1.398, atol=1e-3) +assert np.isclose(B_dp / B_ex, 1.061, atol=1e-3) # last loop value: z = 250 m +assert np.isclose(z_10, 195.2, atol=0.5) +assert np.isclose(ratio_core, 1.48, atol=0.01) +print("Self-check passed.") +``` + +The explorer below shows a circular loop seen edge-on, with its axis vertical. The upper panel compares the exact field lines of the loop (solid) with those of a point dipole with the same moment (dashed), in units of the loop radius $R_L$. The lower-left panel shows $|\vec B|$ on the axis on log–log axes, for the loop radius and current you choose. The lower-right panel shows the ratio of the dipole formula to the exact field, with a line at $10\%$. + +1. Keep $R_L = 50\ \mathrm{m}$ and $I = 10\ \mathrm{A}$ and set $z/R_L = 2$. Check your answers to quiz part (d). +2. In the upper panel, where do the solid and dashed field lines agree, and where do they differ most? What does "far from a compact loop" (W4L2, slide 14) mean in this picture? +3. Change $R_L$ and $I$. Does the curve in the lower-right panel change? Explain why. What does change in the lower-left panel? +4. Find the value of $z/R_L$ where the ratio drops to $1.1$, so that the dipole formula is accurate to within $10\%$. Compare it with your results at $2R_L$ and $5R_L$ in quiz part (d). Then set $z/R_L \approx 1.85$ to check part (e). +```{code-cell} ipython3 +:tags: [remove-input] + +# The HTML contains all controls and drawing code, with no external dependencies. +# An iframe keeps the explorer independent of the page styles. +import html as html_module +from pathlib import Path +from IPython.display import display + +for _candidate in ( + Path("current_loop_lab.html"), + Path("book/2_potential_fields/labs/week4/current_loop_lab.html"), +): + if _candidate.exists(): + explorer_html = _candidate.read_text() + break +else: + from pyodide.http import pyfetch + _r = await pyfetch("current_loop_lab.html") + explorer_html = (await _r.bytes()).decode() + +display({"text/html": ''}, raw=True) +``` \ No newline at end of file diff --git a/book/2_potential_fields/labs/week4/week4_exercises_solutions.md b/book/2_potential_fields/labs/week4/week4_exercises_solutions.md new file mode 100644 index 0000000..f822af3 --- /dev/null +++ b/book/2_potential_fields/labs/week4/week4_exercises_solutions.md @@ -0,0 +1,424 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- +# Lab 4: Electrostatic and Magnetic Fields (Solutions) +## 1. Explore a spherical capacitor + +Between the shells the region is free space, so the potential obeys Laplace's equation. With spherical symmetry this reduces to the radial form used in the {doc}`week 4 quiz `, whose solution is $V(r) = A + B/r$. The two constants follow from the boundary conditions $V(R_E)=0$ and $V(R_I)=V_o$: +```{math} +\boxed{B = \frac{V_o}{1/R_I - 1/R_E}}, \qquad \boxed{A = -\frac{B}{R_E}}, +\qquad +V(r) = V_o\,\frac{1/R_E - 1/r}{1/R_I - 1/R_E}. +``` +The field between the shells is radial, +```{math} +\vec{E} = -\vec{\nabla}V = -\frac{\partial V}{\partial r}\hat{r} = \boxed{\frac{B}{r^2}\,\hat{r}}. +``` +Because the outer shell is at the higher potential, $B<0$: the field points radially **inward**, i.e. downward at the ground, in agreement with the fair-weather field of Exercise 2. + +**1. Reproduce the quiz numbers.** With $R_E = 6370\ \mathrm{km}$, $R_I = 6470\ \mathrm{km}$ and $V_o = 100\ \mathrm{kV}$, +```{math} +\frac{1}{R_I}-\frac{1}{R_E} = \frac{R_E-R_I}{R_I R_E} = -2.427\cdot 10^{-9}\ \mathrm{m^{-1}}, +``` +```{math} +B = \frac{10^{5}}{-2.427\cdot 10^{-9}} = \boxed{-4.12\cdot 10^{13}\ \mathrm{V\,m}}, +\qquad +A = -\frac{B}{R_E} = \boxed{6.47\cdot 10^{6}\ \mathrm{V}}, +``` +matching parts (b) and (d) of the quiz. At $50\ \mathrm{km}$ altitude, $r = 6420\ \mathrm{km}$: +```{math} +\vec{E} = \frac{B}{r^2}\hat{r} = \frac{-4.12\cdot 10^{13}}{(6.42\cdot 10^6)^2}\hat{r} += \boxed{-1.00\ \mathrm{V/m}\ \hat{r}}, +``` +a field of $1.00\ \mathrm{V/m}$ pointing towards the Earth, as in part (e). + +```{note} +The explorer reports $B$ in $\mathrm{V\,km}$, because it works with radii in kilometres: it shows $-4.12\cdot 10^{10}\ \mathrm{V\,km}$, which is the same number as $-4.12\cdot 10^{13}\ \mathrm{V\,m}$. +``` + +**2. Move the outer shell farther away.** Writing the gap as $d = R_I - R_E$, +```{math} +B = \frac{V_o}{1/R_I - 1/R_E} = -\,\frac{V_o R_E R_I}{d}, +``` +so $|B|$ **shrinks** as $R_I$ grows at fixed $V_o$, and with it the field at any fixed radius. Numerically, at the Earth's surface: $1.02\ \mathrm{V/m}$ for $d = 100\ \mathrm{km}$, $0.52\ \mathrm{V/m}$ for $200\ \mathrm{km}$, $0.12\ \mathrm{V/m}$ for $1000\ \mathrm{km}$. The field is not fixed by $V_o$ alone because the field is the *rate* at which the potential changes with distance, and the same $100\ \mathrm{kV}$ is now spread over a thicker gap. For a thin gap, $d \ll R_E$, the shells are almost parallel plates and +```{math} +|\vec{E}| \approx \frac{V_o}{d} = \frac{10^5\ \mathrm{V}}{10^5\ \mathrm{m}} = 1\ \mathrm{V/m}, +``` +which is why the answer to question 1 came out so close to $1\ \mathrm{V/m}$. As $R_I\to\infty$ the field does not vanish but tends to that of an isolated charged sphere, $|B| \to V_o R_E$. + +**3. Increase $V_o$ toward 200 kV.** Both $A$ and $B$ are proportional to $V_o$, so at every radius +```{math} +|\vec{E}| = \frac{|B|}{r^2} \propto V_o . +``` +The relationship is **linear**: doubling $V_o$ from $100$ to $200\ \mathrm{kV}$ doubles the field at $50\ \mathrm{km}$ altitude from $1.00$ to $2.00\ \mathrm{V/m}$. This is a direct consequence of Laplace's equation being linear, so scaling the boundary values scales the whole solution. + +**4. Move the probe outside $R_I$ and inside $R_E$.** Outside the outer shell the explorer shows $V = V_o$ and $E = 0$: the two shells carry equal and opposite charges, so any sphere enclosing both contains zero net charge and Gauss's law gives no flux, hence no field. Inside the inner shell $V = 0$ and $E = 0$, as in the interior of any conductor in electrostatic equilibrium. In both regions the potential is constant, consistent with each shell being an equipotential surface: the entire field lives in the gap between them. + +```{code-cell} ipython3 +import numpy as np + +R_E, R_I, V_o = 6370e3, 6470e3, 100e3 # m, m, V + +B = V_o / (1 / R_I - 1 / R_E) +A = -B / R_E +r = 6420e3 # 50 km altitude +print(f"A = {A:.3e} V, B = {B:.3e} V m, E(50 km) = {B / r**2:+.2f} V/m") +print(f"thin-gap estimate V_o/d = {V_o / (R_I - R_E):.2f} V/m") + +for R in (6470e3, 6570e3, 7370e3): # question 2: a thicker gap + b = V_o / (1 / R - 1 / R_E) + print(f" d = {(R - R_E)/1e3:6.0f} km -> |E| at the ground = {abs(b)/R_E**2:.3f} V/m") + +# self-check against the quiz +assert np.isclose(B, -4.12e13, rtol=1e-3) and np.isclose(A, 6.47e6, rtol=1e-3) +assert np.isclose(B / r**2, -1.00, atol=5e-3) +print("Matches the quiz values for A, B and E(50 km).") +``` + +## 2. Charges in the fair-weather field + +On a clear day, the air above flat, open ground carries a downward electric field (W4L1, slides 16–17): +```{math} +\vec{E} \approx -E_0\,\hat{z}, \qquad E_0 \approx 100\ \mathrm{V/m}, \qquad V(z) = E_0 z \quad \text{with } V(0) = 0. +``` +Cosmic rays continuously ionise the air, producing free electrons and positive ions such as $\mathrm{N_2^+}$. Wind also lifts charged mineral dust from deserts into the atmosphere. Use $e = 1.602\cdot 10^{-19}\ \mathrm{C}$, $g = 9.81\ \mathrm{m/s^2}$ and $1\ \mathrm{eV} = 1.602\cdot 10^{-19}\ \mathrm{J}$ (the energy an elementary charge gains across $1\ \mathrm{V}$). + +Parts (a)–(d) of this exercise are question 2 of the {doc}`week 4 quiz `. Work through them first; the Python cell and the explorer below let you check those answers and extend them to part (e). + +(e) In the undisturbed fair-weather field, the potential difference between $z=0$ and $z=2\ \mathrm{m}$ is $200\ \mathrm{V}$ (quiz part (a)). You are standing on the ground and are about $2\ \mathrm{m}$ tall. Is there a $200\ \mathrm{V}$ potential difference between your head and your feet? Sketch how the equipotentials change around you and explain your reasoning. *Hint:* you are a conductor connected to the ground (W4L1, slide 14). + +**(e)** No. Your body is a conductor connected to the ground, so in electrostatic equilibrium it is an equipotential with $V = 0$ (W4L1, slides 14–15). Charge redistributes (negative charge gathers near your head) until the field inside you vanishes. That is why you feel nothing. + +The equipotentials that would have crossed your body are pushed up and over it. They crowd together above your head and spread apart near your feet. The field is therefore **stronger above you** and weaker close to your feet. For the grounded hemisphere in the explorer, the field at the top is +```{math} +\vec{E}(0,0,a) = -E_0\left[1 - 1 + 3\right]\hat{z} = -3E_0\,\hat{z}, +``` +three times the fair-weather value, whatever the size of the object. With the outward normal $\hat{z}$ at the top and $E_{\perp,\mathrm{outside}}=\sigma_q/\epsilon_0$ (W4L1, slide 15), the induced surface charge there is +```{math} +\sigma_q = \epsilon_0 E_{\perp,\mathrm{outside}} = -3\epsilon_0E_0 \approx -2.7\cdot 10^{-9}\ \mathrm{C/m^2}, +``` +three times the fair-weather ground value $\sigma_q=-\epsilon_0E_0\approx-8.9\cdot 10^{-10}\ \mathrm{C/m^2}$. The same effect concentrates the field on trees, masts and mountain tops. It is why lightning rods are placed on the highest point, and why St Elmo's fire glows at mast tips during thunderstorms. + +The potential of the hemisphere is the uniform field plus a dipole term $-E_0 a^3 z/r^3$. The hemisphere and its mirror image below the ground together form a full sphere, which is the same kind of dipole construction as the image charge in W4L1, slide 24. + +### Check your answers with Python + +```{code-cell} ipython3 +import numpy as np + +e = 1.602e-19 # elementary charge [C] +E0 = 100.0 # fair-weather field strength [V/m] +g = 9.81 # gravitational acceleration [m/s^2] + +def V_fair(z): + """Fair-weather potential above flat ground, V(0) = 0.""" + return E0 * z + +# (b), (c): move each particle from z = 0 to z = 10 m +dV = V_fair(10.0) - V_fair(0.0) +for name, q in [("electron", -e), ("N2+ ion ", +e)]: + dU = q * dV # change in potential energy [J] + W = -dU # work done by the field [J] + Fz = q * (-E0) # z-component of F = qE, with E = -E0 z_hat [N] + print(f"{name}: dV = {dV:.0f} V, dU = {dU:+.2e} J = {dU/e:+.0f} eV, " + f"W_field = {W:+.2e} J, F_z = {Fz:+.1e} N") + +# (d): dust grain levitated by the fair-weather field +a_d, rho_d = 1e-6, 2650.0 # radius [m], density [kg/m^3] +m_d = 4/3 * np.pi * a_d**3 * rho_d +q_d = m_d * g / E0 +print(f"m = {m_d:.2e} kg, |q| = {q_d:.2e} C = {q_d/e:.0f} excess electrons") + +# self-check +assert np.isclose(V_fair(2.0), 200.0), "V(2 m) should be 200 V" +assert np.isclose(q_d / e, 6.8e3, rtol=0.02), "check the mass or the force balance" +print("Self-check passed.") +``` + +The explorer below shows the fair-weather field over flat ground. You can add a grounded conducting hemisphere of radius $a$, a crude model of a person, a tree or a small hill. Its potential is +```{math} +V(\vec{r}) = E_0 z\left(1 - \frac{a^3}{r^3}\right), \qquad z \geq 0,\ r \geq a. +``` +The upper panel shows the field strength $|\vec{E}|/E_0$ in colour, the equipotentials in white (every $E_0\cdot 1\ \mathrm{m}$), the field lines in grey, and the force $\vec{F} = q\vec{E}$ on the test charge as an arrow. The lower panel shows $V(z)$ and $U(z)/e$ along the vertical line through the test charge. + +1. With $a = 0$, move the test charge up and down. Check your answers to (a) and (b). +2. Switch between the electron and the ion. Which quantities change, and which stay the same? (W4L1, slide 9) +3. Set $a = 1\ \mathrm{m}$. Where do the equipotentials crowd together? Read $|\vec{E}|$ just above the top of the object and near its base. Use this to check your sketch for (e). + +```{code-cell} ipython3 +:tags: [remove-input] + +# The HTML contains all controls and drawing code, with no external dependencies. +# An iframe keeps the explorer independent of the page styles. +import html as html_module +from pathlib import Path +from IPython.display import display + +for _candidate in ( + Path("fair_weather_lab.html"), + Path("book/2_potential_fields/labs/week4/fair_weather_lab.html"), +): + if _candidate.exists(): + explorer_html = _candidate.read_text() + break +else: + from pyodide.http import pyfetch + _r = await pyfetch("fair_weather_lab.html") + explorer_html = (await _r.bytes()).decode() + +display({"text/html": ''}, raw=True) +``` + +## 3. Explore Earth's dipole field + +Far from a compact current system, its magnetic field is that of a dipole (W4L2, slides 14–15). Earth's main field is modelled as a dipole at Earth's centre. As in the lecture, let $\hat m=\hat z$, let $\theta$ be the angle measured from $\hat m$, and work in the $x$–$z$ plane with $\hat r=\sin\theta\,\hat x+\cos\theta\,\hat z$ (slide 22). The field is +```{math} +\vec B = B_*\left(\frac{R}{r}\right)^3\left[3(\hat m\cdot\hat r)\,\hat r-\hat m\right], +\qquad B_*=\frac{\mu_0|\vec m|}{4\pi R^3}. +``` +For Earth, take $R=a=6371\ \mathrm{km}$ and $B_*\approx 29.7\ \mu\mathrm{T}$ (called $B_0$ in the teachbook section *Earth as a Magnetic Dipole*). For the present polarity, $\hat m$ points toward the **southern** end of the dipole axis: $\theta=0$ is the southern end, $\theta=\pi$ the northern end, and $\theta=\pi/2$ the dipole equator. + +Parts (a)–(d) of this exercise are question 3 of the {doc}`week 4 quiz `. Work through them first; the Python cell and the explorer below let you check those answers and extend them to part (e). + +(e) The quiz quotes the component form of the dipole field; here you derive it. Repeat part (b) of the quiz for a general $\theta$ at $r=a$. +1. Write $\hat z=\cos\theta\,\hat r-\sin\theta\,\hat\theta$, with $\hat\theta=\cos\theta\,\hat x-\sin\theta\,\hat z$ pointing along the ground toward the northern end of the axis. Show that the field has a radial component $B_r=2B_*\cos\theta$ and a horizontal component $B_\theta=B_*\sin\theta$. +2. Use the dipole latitude $\lambda_m=\theta-\pi/2$ (positive in the northern hemisphere) to show that the angle $I$ below the horizontal satisfies $\tan I=2\tan\lambda_m$. Check it against quiz part (b). +3. A navigator measures $I=70^\circ$. What is the dipole latitude? Near which latitudes does a small error in $I$ matter least? + + +**(e) 1.** From slide 17, at $r=a$: $\vec B/B_*=3\cos\theta\,\hat r-\hat z$. Check the given decomposition: +```{math} +\cos\theta\,\hat r-\sin\theta\,\hat\theta +=\cos\theta(\sin\theta\,\hat x+\cos\theta\,\hat z)-\sin\theta(\cos\theta\,\hat x-\sin\theta\,\hat z)=\hat z. +``` +Substituting it gives +```{math} +\frac{\vec B}{B_*}=3\cos\theta\,\hat r-\cos\theta\,\hat r+\sin\theta\,\hat\theta +=2\cos\theta\,\hat r+\sin\theta\,\hat\theta, +``` +so $\boxed{B_r=2B_*\cos\theta}$ and $\boxed{B_\theta=B_*\sin\theta}$. These are the components given in the teachbook section *Earth as a Magnetic Dipole* (with $B_0=B_*$). + +**(e) 2.** With $\theta=\lambda_m+\pi/2$: $\cos\theta=-\sin\lambda_m$ and $\sin\theta=\cos\lambda_m$. The downward and northward components are +```{math} +B_\mathrm{down}=-B_r=2B_*\sin\lambda_m,\qquad B_\theta=B_*\cos\lambda_m, +``` +so +```{math} +\tan I=\frac{B_\mathrm{down}}{B_\theta}=\boxed{2\tan\lambda_m}. +``` +This relation appears in the optional teachbook box *Connect to magnetic inclination*. At $\lambda_m=45^\circ$: $\tan I=2$, so $I=63.4^\circ$, as in quiz part (b). + +**(e) 3.** $\lambda_m=\arctan\left(\tfrac12\tan70^\circ\right)=\arctan(1.37)=\boxed{53.9^\circ\ \mathrm{N}}$. This is a dipole latitude. The real axis is tilted and the real field has non-dipole parts, so it is not the geographic latitude (teachbook). In the lower-right panel of the explorer, the angle changes fastest with $\theta$ near the equator, where its slope is 2. There a $1^\circ$ error in $I$ shifts the latitude by only $0.5^\circ$. Near the poles the slope drops to $0.5$, and the same error shifts the latitude by $2^\circ$. + +### Check your answers with Python + +```{code-cell} ipython3 +import numpy as np + +B_star = 29.7e-6 # B_* for Earth [T] +a = 6371e3 # R = a, Earth's reference radius [m] +m_hat = np.array([0.0, 1.0]) # (x, z): m_hat = z_hat, toward the SOUTHERN end of the axis + +def B_dipole(theta, r): + """Dipole field (Bx, Bz) [T] at polar angle theta (from m_hat) and distance r [m].""" + r_hat = np.array([np.sin(theta), np.cos(theta)]) + return B_star * (a / r)**3 * (3 * np.dot(m_hat, r_hat) * r_hat - m_hat) + +def below_horizontal(theta, r): + """Angle [deg] between B and the local horizontal, positive when B points into the ground.""" + r_hat = np.array([np.sin(theta), np.cos(theta)]) + B = B_dipole(theta, r) + B_radial = np.dot(B, r_hat) # component of B along r_hat (positive = out of the ground) + return np.degrees(np.arcsin(-B_radial / np.linalg.norm(B))) + +# (a), (b): at the surface +for name, th in [("southern end", 0.0), ("dipole equator", np.pi/2), + ("northern end", np.pi), ("45 deg N", 3*np.pi/4)]: + B = B_dipole(th, a) + Bx, Bz = np.round(B / B_star, 2) + 0.0 # + 0.0 avoids printing -0.00 + I = round(below_horizontal(th, a), 1) + 0.0 + print(f"{name:15s} B/B* = ({Bx:+.2f}, {Bz:+.2f}), " + f"|B| = {np.linalg.norm(B)*1e6:5.1f} uT, below horizontal = {I:+6.1f} deg") + +# (c): Swarm at 450 km altitude above 45 deg N +r_swarm = a + 450e3 +print(f"(c) |B| at Swarm altitude = {np.linalg.norm(B_dipole(3*np.pi/4, r_swarm))*1e6:.1f} uT," + f" below horizontal = {below_horizontal(3*np.pi/4, r_swarm):.1f} deg") + +# (d): distance at which the field has dropped to 1% of its surface value +r_1pct = a * 100**(1/3) +print(f"(d) r = {r_1pct/a:.2f} a = {r_1pct/1e3:.0f} km") + +# (e): dipole latitude for a measured angle I = 70 deg, from tan I = 2 tan(lambda_m) +lam_nav = np.arctan(np.tan(np.radians(70)) / 2) # [rad] +print(f"(e) I = 70 deg -> lambda_m = {np.degrees(lam_nav):.1f} deg N") + +# self-check +assert np.isclose(np.linalg.norm(B_dipole(np.pi/2, a)), B_star) +assert np.isclose(np.linalg.norm(B_dipole(3*np.pi/4, a)), 47.0e-6, rtol=1e-3) +assert np.isclose(below_horizontal(3*np.pi/4, a), 63.43, atol=0.01) +assert np.isclose(np.linalg.norm(B_dipole(3*np.pi/4, r_swarm)), 38.3e-6, rtol=2e-3) +assert np.isclose(np.linalg.norm(B_dipole(np.pi, r_1pct)) / np.linalg.norm(B_dipole(np.pi, a)), 0.01) +assert np.isclose(np.degrees(lam_nav), 53.95, atol=0.01) +print("Self-check passed.") +``` + +The explorer below draws the dipole field lines in the $x$–$z$ plane, oriented as in the lecture ($\hat m=\hat z$ up the page, so the southern end of Earth's axis is at the top). Choose a probe point with $\theta$ and $r/a$. At the probe, the blue, red and black arrows show the head-to-tail construction of the bracket $3(\hat m\cdot\hat r)\hat r-\hat m$. The dashed line is the local horizontal. The lower-left panel shows $|\vec B|$ along the radial line through the probe on log–log axes. The lower-right panel shows the angle below the horizontal and $|\vec B|/B_*$ at the surface as functions of $\theta$. + +1. At $r/a=1$, set $\theta=0^\circ$, $90^\circ$ and $135^\circ$ to check your answers to quiz parts (a) and (b), then $180^\circ$ to see the northern end. +2. Press *Swarm altitude*. Which numbers change, and which stay the same? Do the arrows at the probe change? (W4L2, slide 15) +3. In the lower-left panel, why is the curve a straight line? Read off where it crosses the $1\%$ line and compare with quiz part (d). By what factor does $|\vec B|$ drop between $r/a=1$ and $2$? (W4L2, slide 18) +4. In the lower-right panel, where is the field vertical, where is it horizontal, and where is $|\vec B|$ largest and smallest? Where does the angle change fastest with $\theta$? Relate this to part (e). + +**Answers** + +1. The status line shows the quiz values: bracket $(0,2)$ and $59.4\ \mu\mathrm{T}$ out of the ground at $0^\circ$; $(0,-1)$ and $29.7\ \mu\mathrm{T}$ horizontal at $90^\circ$; $(0,2)$ and $59.4\ \mu\mathrm{T}$ into the ground at $180^\circ$; $(-1.50,0.50)$, $47.0\ \mu\mathrm{T}$ and $63.4^\circ$ below the horizontal at $135^\circ$. +2. At Swarm altitude, $(a/r)^3$ drops to $0.816$, so $|\vec B|$ and $B_r$ fall to $38.3\ \mu\mathrm{T}$ and $-34.3\ \mu\mathrm{T}$. The bracket, the arrows and the angle below the horizontal ($63.4^\circ$) do not change: the bracket depends only on directions (W4L2, slide 15). +3. $|\vec B|\propto r^{-3}$, so $\log|\vec B|=\text{const}-3\log r$: a straight line with slope $-3$. It crosses the $1\%$ line at $r/a\approx4.6$, as in quiz part (d). From $r/a=1$ to $2$, $|\vec B|$ drops by a factor of $8$ (W4L2, slide 18). +4. The field is vertical at $\theta=0^\circ$ and $180^\circ$ (angle $\mp90^\circ$) and horizontal at $\theta=90^\circ$. $|\vec B|$ is largest at the poles ($2B_*$) and smallest at the equator ($B_*$). The angle changes fastest near $\theta=90^\circ$, which is why the dip is the most sensitive latitude indicator near the dipole equator (part (e) 3). + +```{code-cell} ipython3 +:tags: [remove-input] + +# The HTML contains all controls and drawing code, with no external dependencies. +# An iframe keeps the explorer independent of the page styles. +import html as html_module +from pathlib import Path +from IPython.display import display + +for _candidate in ( + Path("earth_dipole_lab.html"), + Path("book/2_potential_fields/labs/week4/earth_dipole_lab.html"), +): + if _candidate.exists(): + explorer_html = _candidate.read_text() + break +else: + from pyodide.http import pyfetch + _r = await pyfetch("earth_dipole_lab.html") + explorer_html = (await _r.bytes()).decode() + +display({"text/html": ''}, raw=True) +``` + +## 4. Explore a current loop and its dipole field + +Far from a compact current loop, its magnetic field is that of a dipole (W4L2, slide 14). A circular loop carrying current $I$ around an area $A$ has the magnetic moment +```{math} +\vec m = IA\,\hat n, +``` +where $\hat n$ is the normal to the loop given by the right-hand rule: curl the fingers along the current, and the thumb gives $\hat n$. Use $\mu_0 = 4\pi\cdot10^{-7}\ \mathrm{T\,m/A}$. + +Parts (a)–(d) of this exercise are question 4 of the {doc}`week 4 quiz `. Work through them first; the Python cell and the explorer below let you check those answers and extend them to part (e). + +(e) Return to the core loop of quiz part (b). An observer stands on Earth's surface above the northern end of the axis, at distance $z = a$ from the centre of the loop. How large is the error of the dipole formula there? How far from Earth's centre, in units of $a$, would the observer have to be for the dipole formula to be accurate to within $10\%$? What does this tell you about the single-loop picture of the geodynamo? + +**(e)** With $z = a$ and $R_c = 3480\ \mathrm{km}$, $z/R_c = 1.83$ and +```{math} +\frac{B_\mathrm{dip}}{B_\mathrm{loop}} = \left(1+\frac{R_c^2}{a^2}\right)^{3/2} = (1+0.298)^{3/2} = \boxed{1.48}. +``` +At Earth's surface, the dipole formula would be **48% too large** for a single loop the size of the core. From explorer question 4, $10\%$ accuracy needs $z = 3.9\,R_c = 1.36\cdot10^{4}\ \mathrm{km} \approx \boxed{2.1\,a}$. + +So a single loop as large as the core would *not* look like a centred dipole at Earth's surface, yet the observed main field is dominated by its dipole part (teachbook, *Earth as a Magnetic Dipole*). The real geodynamo currents are spread through the core rather than concentrated in one loop at its edge. The single loop in quiz part (b) is therefore only an order-of-magnitude estimate of the current, not a model of its geometry. This is why the teachbook calls the dipole an *equivalent* description of the core currents. + +### Check your answers with Python + +```{code-cell} ipython3 +import numpy as np + +mu0 = 4e-7 * np.pi # [T m/A] +a, B_star, R_c = 6371e3, 29.7e-6, 3480e3 # Earth radius [m], B_* [T], outer-core radius [m] + +# (a), (b): Earth's moment and the equivalent core current +m_earth = 4 * np.pi * a**3 * B_star / mu0 # from B_* = mu0 m / (4 pi a^3) [A m^2] +I_core = m_earth / (np.pi * R_c**2) # from m = I * pi R_c^2 [A] +print(f"(a) m = {m_earth:.2e} A m^2 (b) I = {I_core:.2e} A") + +def B_loop_axis(z, I, R): + """Exact field on the axis of a circular loop of radius R [T].""" + return mu0 * I * R**2 / (2 * (R**2 + z**2)**1.5) + +def B_dip_axis(z, m): + """Dipole formula on the axis [T].""" + return mu0 * m / (2 * np.pi * z**3) + +# (c), (d): the survey loop +R_L, I_L = 50.0, 10.0 +m_L = I_L * np.pi * R_L**2 # moment of the survey loop [A m^2] +print(f"(c) m = {m_L:.3g} A m^2") +for z in (100.0, 250.0): # (d): z = 2 R_L and z = 5 R_L + B_ex, B_dp = B_loop_axis(z, I_L, R_L), B_dip_axis(z, m_L) + print(f"(d) at z = {z:.0f} m: exact {B_ex*1e9:.2f} nT, dipole {B_dp*1e9:.2f} nT, " + f"ratio {B_dp/B_ex:.2f}") +z_10 = R_L / np.sqrt(1.1**(2/3) - 1) # height where B_dip / B_loop = 1.1 [m] +print(f" dipole formula within 10% beyond z = {z_10:.0f} m = {z_10/R_L:.1f} R_L") + +# (e): the core loop seen from Earth's surface on the axis +ratio_core = B_dip_axis(a, m_earth) / B_loop_axis(a, I_core, R_c) +print(f"(e) z/R_c = {a/R_c:.2f}: dipole / exact = {ratio_core:.2f}; " + f"10% needs r = {z_10/R_L * R_c / a:.2f} a") + +# self-check +assert np.isclose(m_earth, 7.68e22, rtol=2e-3) and np.isclose(I_core, 2.02e9, rtol=5e-3) +assert np.isclose(m_L, 7.854e4, rtol=1e-3) +assert np.isclose(B_dip_axis(100.0, m_L) / B_loop_axis(100.0, I_L, R_L), 1.398, atol=1e-3) +assert np.isclose(B_dp / B_ex, 1.061, atol=1e-3) # last loop value: z = 250 m +assert np.isclose(z_10, 195.2, atol=0.5) +assert np.isclose(ratio_core, 1.48, atol=0.01) +print("Self-check passed.") +``` + +The explorer below shows a circular loop seen edge-on, with its axis vertical. The upper panel compares the exact field lines of the loop (solid) with those of a point dipole with the same moment (dashed), in units of the loop radius $R_L$. The lower-left panel shows $|\vec B|$ on the axis on log–log axes, for the loop radius and current you choose. The lower-right panel shows the ratio of the dipole formula to the exact field, with a line at $10\%$. + +1. Keep $R_L = 50\ \mathrm{m}$ and $I = 10\ \mathrm{A}$ and set $z/R_L = 2$. Check your answers to quiz part (d). +2. In the upper panel, where do the solid and dashed field lines agree, and where do they differ most? What does "far from a compact loop" (W4L2, slide 14) mean in this picture? +3. Change $R_L$ and $I$. Does the curve in the lower-right panel change? Explain why. What does change in the lower-left panel? +4. Find the value of $z/R_L$ where the ratio drops to $1.1$, so that the dipole formula is accurate to within $10\%$. Compare it with your results at $2R_L$ and $5R_L$ in quiz part (d). Then set $z/R_L \approx 1.85$ to check part (e). + +**Answers** + +1. With $R_L=50\ \mathrm{m}$, $I=10\ \mathrm{A}$ and $z/R_L=2$, the status line gives $B_\mathrm{loop}=11.2\ \mathrm{nT}$, $B_\mathrm{dip}=15.7\ \mathrm{nT}$ and a ratio of $1.40$, as in quiz part (d). +2. A few loop radii away, the solid and dashed lines almost coincide: there the loop is "compact" compared with the distance. They differ most near the wire. The loop's field lines close around the wire, while every dipole line passes through the single point at the centre. Near the loop, its size matters; far away, only its moment $I\pi R_L^2$ does. +3. The ratio curve does not change: $B_\mathrm{dip}/B_\mathrm{loop} = (1+R_L^2/z^2)^{3/2}$ depends only on $z/R_L$. In the lower-left panel both curves shift: at a fixed $z/R_L$ the field scales as $I/R_L$, so a larger current raises the curves and a larger loop lowers them. +4. The ratio drops to $1.1$ at $z/R_L\approx3.9$ (195 m for the survey loop), between the $40\%$ error at $2R_L$ and the $6\%$ error at $5R_L$ found in quiz part (d). Solving $(1+R_L^2/z^2)^{3/2}=1.1$ gives the same value: $z = R_L/\sqrt{1.1^{2/3}-1} = 3.9\,R_L$. At $z/R_L=1.85$ it is about $1.47$, close to the $1.48$ found in part (e) for $z/R_c = 1.83$. +```{code-cell} ipython3 +:tags: [remove-input] + +# The HTML contains all controls and drawing code, with no external dependencies. +# An iframe keeps the explorer independent of the page styles. +import html as html_module +from pathlib import Path +from IPython.display import display + +for _candidate in ( + Path("current_loop_lab.html"), + Path("book/2_potential_fields/labs/week4/current_loop_lab.html"), +): + if _candidate.exists(): + explorer_html = _candidate.read_text() + break +else: + from pyodide.http import pyfetch + _r = await pyfetch("current_loop_lab.html") + explorer_html = (await _r.bytes()).decode() + +display({"text/html": ''}, raw=True) +``` + \ No newline at end of file diff --git a/book/2_potential_fields/labs/week4/week4_quiz.md b/book/2_potential_fields/labs/week4/week4_quiz.md new file mode 100644 index 0000000..8939fc6 --- /dev/null +++ b/book/2_potential_fields/labs/week4/week4_quiz.md @@ -0,0 +1,93 @@ +# Quiz Week 4 + + +## 1. Earth-ionosphere system +The Earth-ionosphere system can be modeled in a simple way by assuming the Earth to be a perfectly conducting sphere of radius $R_E$, surrounded by a thin, perfectly conducting spherical shell with radius $R_I = R_E + 100\ \text{km}$, with free space between them. The surface of the Earth has a potential $\Phi(r=R_E)=0\ \text{V}$, and the ionosphere has potential $\Phi(r=R_I)=V_I$. + +```{figure} figures/simple_ionosphere.png +:width: 35% +``` + +(a) Write the equation you would use to determine the potential in the region $R_E < r < R_I$ in the simplest form possible given the information provided. + +(b) Assume the solution for the potential has the form +```{math} +\Phi(r) = A + \frac{B}{r}. +``` +Find expressions for $A$ and $B$, and write the expression for the potential in these terms. + +(c) Find the expression for the electric field, $\vec{E}$, in the region $R_E < r < R_I$. + + +(d) Find the numerical values of $A$ and $B$ assuming $R_E=6370\ \text{km}$ and $V_I=100\ \text{kV}$. + + +(e) What is the strength of the field at 50 km altitude, and in which direction is it pointing? + + +## 2. The fair-weather field +On a clear day, the air above flat, open ground carries a downward electric field (W4L1, slides 16–17): +```{math} +\vec{E} \approx -E_0\,\hat{z}, \qquad E_0 \approx 100\ \mathrm{V/m}, \qquad V(z) = E_0 z \quad \text{with } V(0) = 0. +``` +Cosmic rays continuously ionise the air, producing free electrons and positive ions such as $\mathrm{N_2^+}$. Wind also lifts charged mineral dust from deserts into the atmosphere. Use $e = 1.602\cdot 10^{-19}\ \mathrm{C}$, $g = 9.81\ \mathrm{m/s^2}$ and $1\ \mathrm{eV} = 1.602\cdot 10^{-19}\ \mathrm{J}$ (the energy an elementary charge gains across $1\ \mathrm{V}$). + +(a) Sketch the equipotentials and field lines for $0 \leq z \leq 10\ \mathrm{m}$. What is the electric potential $V$ at $z = 2\ \mathrm{m}$, given the reference $V(0) = 0$ ? + +(b) An electron ($q=-e$) and an $\mathrm{N_2^+}$ ion ($q=+e$) are each moved from the ground to $z = 10\ \mathrm{m}$. For each, find $\Delta V$, $\Delta U$ (in J and in eV) and the work done by the field, $W_\mathrm{field}$. + +(c) Both particles are released from rest. Which one accelerates upward? In which direction does the resulting current flow? + +(d) A Saharan dust grain (radius $1\ \mu\mathrm{m}$, density $2650\ \mathrm{kg/m^3}$) carries a negative charge. How many excess electrons does it need for the electric force to balance gravity? Does the answer depend on its height in this model? + +## 3. Earth's magnetic field +Far from a compact current system, its magnetic field is that of a dipole (W4L2, slides 14–15). Earth's main field is modelled as a dipole at Earth's centre. As in the lecture, let $\hat m=\hat z$, let $\theta$ be the angle measured from $\hat m$, and work in the $x$–$z$ plane with $\hat r=\sin\theta\,\hat x+\cos\theta\,\hat z$ (slide 22). The field is +```{math} +\vec B = B_*\left(\frac{R}{r}\right)^3\left[3(\hat m\cdot\hat r)\,\hat r-\hat m\right], +\qquad B_*=\frac{\mu_0|\vec m|}{4\pi R^3}. +``` +For Earth, take $R=a=6371\ \mathrm{km}$ and $B_*\approx 29.7\ \mu\mathrm{T}$ (called $B_0$ in the teachbook section *Earth as a Magnetic Dipole*). For the present polarity, $\hat m$ points toward the **southern** end of the dipole axis: $\theta=0$ is the southern end, $\theta=\pi$ the northern end, and $\theta=\pi/2$ the dipole equator. + +Written in the local directions $\hat r$ (outward) and $\hat\theta$ (tangent to the surface, in the direction of increasing $\theta$), the same field is +```{math} +\frac{\vec B}{B_*} = \left(\frac{R}{r}\right)^3\left(2\cos\theta\,\hat r + \sin\theta\,\hat\theta\right), +\qquad\text{that is}\qquad +B_r = 2B_*\left(\frac{R}{r}\right)^3\cos\theta, +\quad +B_\theta = B_*\left(\frac{R}{r}\right)^3\sin\theta . +``` +You may use either form. + +```{figure} figures/earth_dipole_setup.png +:width: 45% + +Geometry of the dipole model, as in W4L2, slides 17 and 22: $\hat m=\hat z$ points up the page, $\theta$ is measured from $\hat m$, and the grey arrows show $\hat r$ at the points used in (a) and (b). The dashed circle is Earth's surface, $r=a$. +``` + +(a) At the surface, $r=a$, find $\vec B/B_*$ at $\theta=0$ and $\pi/2$, and give $|\vec B|$ in $\mu\mathrm{T}$. At each point, determine whether $\vec B$ points into the Earth, out of the Earth or is tangent to the Earth's surface. Using $B_r\propto\cos\theta$, in which hemisphere does the field enter Earth? + +(b) At $r=a$ and $\theta=3\pi/4$ (dipole latitude $45^\circ$ N), construct $\vec B/B_*$ head to tail from $3(\hat m\cdot\hat r)\hat r$ and $-\hat m$ (W4L2, slide 16). Find $|\vec B|$ in $\mu\mathrm{T}$ and the angle between $\vec B$ and the local horizontal. *Hint:* use $\vec B\cdot\hat r=|\vec B|\cos\alpha$, where $\alpha$ is the angle between $\vec B$ and $\hat r$. The local horizontal is perpendicular to $\hat r$, so the angle between $\vec B$ and the horizontal is $|90^\circ-\alpha|$. + +(c) ESA's Swarm satellites measure the Earth's magnetic field at about $450\ \mathrm{km}$ altitude. Consider a point directly above the location in (b), i.e. at the same dipole latitude. What happens to the magnitude $|\vec B|$ and direction of $\vec B$? + +(d) Above the northern end of the dipole axis, at what distance from Earth's centre has the magnetic field magnitude $|\vec B|$ decreased to $1\%$ of its value at Earth's surface ? + +## 4. A current loop as a magnetic dipole +Far from a compact current loop, its magnetic field is that of a dipole (W4L2, slide 14). A circular loop carrying current $I$ around an area $A$ has the magnetic moment +```{math} +\vec m = IA\,\hat n, +``` +where $\hat n$ is the normal to the loop given by the right-hand rule: curl the fingers along the current, and the thumb gives $\hat n$. Use $\mu_0 = 4\pi\cdot10^{-7}\ \mathrm{T\,m/A}$. + +(a) In question 3, the magnetic field at Earth's dipole equator and surface was described by $B_*=\mu_0|\vec m|/(4\pi a^3)\approx 29.7\ \mu\mathrm{T}$, with $a=6371\ \mathrm{km}$. Find Earth's dipole moment $|\vec m|$. + +(b) Earth's field is generated by electric currents in the liquid outer core (the geodynamo). As a size estimate, replace these currents by a single circular loop in the dipole's equatorial plane, with the radius of the outer core, $R_c = 3480\ \mathrm{km}$. What current $I$ is needed? Seen from above the northern end of the dipole axis, does the current circulate clockwise or counterclockwise? *Hint:* Use the right-hand rule: point your right thumb in the direction of $\hat m$, toward the southern end of Earth's dipole axis. Your curled fingers show the direction of the current. + +(c) A geophysicist lays out a circular wire loop of radius $R_L = 50\ \mathrm{m}$ on flat ground and drives a current $I = 10\ \mathrm{A}$ through it. Find its magnetic moment. On the axis of the loop, at height $z$ above its centre, the exact field is (you do not need to derive it) +```{math} +B_\mathrm{loop}(z) = \frac{\mu_0 I R_L^2}{2\left(R_L^2+z^2\right)^{3/2}}. +``` +Starting from the exact loop field, show that when $z \gg R_L$, the field reduces to the dipole field on the axis $B_\mathrm{dip}(z)=\dfrac{\mu_0|\vec m|}{2\pi z^3}$ (corresponding to $\theta=0$ case of question 3). + +(d) Find $B_\mathrm{loop}$ and $B_\mathrm{dip}$ in nT at $z = 100\ \mathrm{m}$ $(=2R_L)$ and at $z = 250\ \mathrm{m}$ $(=5R_L)$. By how many percent does the dipole formula overestimate the field at each height? Based on these results, for what approximate values of $ z/R_L $ does the dipole approximation become reasonably accurate? *Hint:* $B_\mathrm{dip}/B_\mathrm{loop} = \left(1+R_L^2/z^2\right)^{3/2}$. + \ No newline at end of file diff --git a/book/2_potential_fields/labs/week4/week4_quiz_solutions.md b/book/2_potential_fields/labs/week4/week4_quiz_solutions.md new file mode 100644 index 0000000..a854b6f --- /dev/null +++ b/book/2_potential_fields/labs/week4/week4_quiz_solutions.md @@ -0,0 +1,279 @@ +# Quiz Week 4 (Solutions) + + +## 1. Earth-ionosphere system +The Earth-ionosphere system can be modeled in a simple way by assuming the Earth to be a perfectly conducting sphere of radius $R_E$, surrounded by a thin, perfectly conducting spherical shell with radius $R_I = R_E + 100\ \text{km}$, with free space between them. The surface of the Earth has a potential $\Phi(r=R_E)=0\ \text{V}$, and the ionosphere has potential $\Phi(r=R_I)=V_I$. + +```{figure} figures/simple_ionosphere.png +:width: 35% +``` + +(a) Write the equation you would use to determine the potential in the region $R_E < r < R_I$ in the simplest form possible given the information provided. + +Since the region between the Earth and ionosphere is modeled as free space, we use Laplace's equation: +```{math} +\nabla^2\Phi = 0. +``` +The problem has spherical symmetry (there is no dependance on $\phi$ or $\theta$). Thus the equation reduces to +```{math} +\boxed{\frac{\partial}{\partial r} \left( r^2 \frac{\partial \Phi}{\partial r} \right) = 0} +``` + +(b) Assume the solution for the potential has the form +```{math} +\Phi(r) = A + \frac{B}{r}. +``` +Find expressions for $A$ and $B$, and write the expression for the potential in these terms. + +Applying the boundary conditions $\Phi(r=R_E)=0$ and $\Phi(r=R_I)=V_I$, we get +```{math} +A = \frac{-B}{R_E} +``` +and +```{math} +\boxed{B = \frac{V_I}{1/R_I - 1/R_E}} +``` +This gives us +```{math} +\boxed{A = \frac{V_I}{R_E(1/R_I - 1/R_E)}} +``` +and +```{math} +\boxed{\Phi(r) = V_I\frac{1/R_E - 1/r}{1/R_I - 1/R_E}} +``` + +(c) Find the expression for the electric field, $\vec{E}$, in the region $R_E < r < R_I$. + +```{math} +\begin{aligned} +\vec{E} &= -\vec{\nabla}\Phi \\ + &= -\frac{\partial}{\partial r} \Phi(r)\ \hat{r} \\ + &= -\left(\frac{-B}{r^2}\right)\ \hat{r} \\ + &= \boxed{\frac{B}{r^2}\ \hat{r}} +\end{aligned} +``` + +(d) Find the numerical values of $A$ and $B$ assuming $R_E=6370\ \text{km}$ and $V_I=100\ \text{kV}$. + +```{math} +\begin{aligned} +B &= \frac{(100\cdot 10^3)}{1/(6470\cdot 10^3) - 1/(6370\cdot 10^3)} \\ + &= \boxed{-4.12 \cdot 10^{13}\ \mathrm{V \cdot m}} +\end{aligned} +``` + +```{math} +\begin{aligned} +A &= \frac{-(-4.12 \cdot 10^{13})}{(6370\cdot 10^3)} \\ + &= \boxed{6.47 \cdot 10^6\ \mathrm{V}} +\end{aligned} +``` + +(e) What is the strength of the field at 50 km altitude, and in which direction is it pointing? + +```{math} +\begin{aligned} +\vec{E} &= \frac{B}{r^2} \hat{r} \\ + &= \frac{(-4.12 \cdot 10^{13})}{(6420\cdot 10^3)^2} \hat{r} \\ + &= \boxed{-1.00\ \mathrm{V/m}\ \hat{r}} +\end{aligned} +``` +The field points radially inward (ie. down), from high potential to low. + + +## 2. The fair-weather field +On a clear day, the air above flat, open ground carries a downward electric field (W4L1, slides 16–17): +```{math} +\vec{E} \approx -E_0\,\hat{z}, \qquad E_0 \approx 100\ \mathrm{V/m}, \qquad V(z) = E_0 z \quad \text{with } V(0) = 0. +``` +Cosmic rays continuously ionise the air, producing free electrons and positive ions such as $\mathrm{N_2^+}$. Wind also lifts charged mineral dust from deserts into the atmosphere. Use $e = 1.602\cdot 10^{-19}\ \mathrm{C}$, $g = 9.81\ \mathrm{m/s^2}$ and $1\ \mathrm{eV} = 1.602\cdot 10^{-19}\ \mathrm{J}$ (the energy an elementary charge gains across $1\ \mathrm{V}$). + +(a) Sketch the equipotentials and field lines for $0 \leq z \leq 10\ \mathrm{m}$. What is the electric potential $V$ at $z = 2\ \mathrm{m}$, given the reference $V(0) = 0$ ? + +**(a)** The equipotentials are horizontal planes spaced evenly: every metre up adds $100\ \mathrm{V}$. The field lines are vertical, point downward and are equally spaced, so the field is uniform. At head height, +```{math} +V(2\ \mathrm{m}) = E_0 z = (100)(2) = \boxed{200\ \mathrm{V}}. +``` +The potential increases upward, while $\vec{E}$ points down, from high to low potential. + +(b) An electron ($q=-e$) and an $\mathrm{N_2^+}$ ion ($q=+e$) are each moved from the ground to $z = 10\ \mathrm{m}$. For each, find $\Delta V$, $\Delta U$ (in J and in eV) and the work done by the field, $W_\mathrm{field}$. + +**(b)** The potential difference does not depend on the test charge: +```{math} +\Delta V = V(10\ \mathrm{m}) - V(0) = \boxed{1000\ \mathrm{V}}. +``` +Using $\Delta U = q\Delta V$ and $W_\mathrm{field} = -\Delta U$ (W4L1, slide 13): + +| | $q$ | $\Delta U$ | $W_\mathrm{field}$ | +|---|---|---|---| +| electron | $-e$ | $-1.60\cdot 10^{-16}\ \mathrm{J} = -1000\ \mathrm{eV}$ | $+1.60\cdot 10^{-16}\ \mathrm{J}$ | +| $\mathrm{N_2^+}$ ion | $+e$ | $+1.60\cdot 10^{-16}\ \mathrm{J} = +1000\ \mathrm{eV}$ | $-1.60\cdot 10^{-16}\ \mathrm{J}$ | + +Moving up the electron *loses* potential energy, because the field does positive work on it. The ion *gains* potential energy, because the field works against the motion. Same $\Delta V$, opposite energies. + +(c) Both particles are released from rest. Which one accelerates upward? In which direction does the resulting current flow? + +**(c)** The force is $\vec{F} = q\vec{E} = q(-E_0\hat{z})$. +- Electron: $\vec{F} = (-e)(-E_0\hat{z}) = +eE_0\hat{z} = +1.6\cdot 10^{-17}\ \mathrm{N}\,\hat{z}$. It **accelerates upward**, toward lower potential energy. +- Ion: $\vec{F} = -eE_0\hat{z}$. It accelerates downward. +Positive charge moving down and negative charge moving up both give a **downward** current. This is the small fair-weather current of the global atmospheric electrical circuit, which flows downward through fair-weather regions because air is a poor, but not perfect, insulator. Thunderstorms help maintain the potential difference between the upper atmosphere and the ground that drives it (W4L1, slide 16). + +(d) A Saharan dust grain (radius $1\ \mu\mathrm{m}$, density $2650\ \mathrm{kg/m^3}$) carries a negative charge. How many excess electrons does it need for the electric force to balance gravity? Does the answer depend on its height in this model? + +**(d)** The mass of the grain is +```{math} +m = \tfrac{4}{3}\pi a^3 \rho = \tfrac{4}{3}\pi (10^{-6})^3 (2650) = 1.11\cdot 10^{-14}\ \mathrm{kg}. +``` +A negative charge feels an upward force (see (c)), so it can balance gravity when $|q|E_0 = mg$: +```{math} +|q| = \frac{mg}{E_0} = \frac{(1.11\cdot 10^{-14})(9.81)}{100} = 1.09\cdot 10^{-15}\ \mathrm{C}, +\qquad N = \frac{|q|}{e} \approx \boxed{6.8\cdot 10^{3}\ \text{electrons}}. +``` +In this model, $\vec{E}$ is uniform, so the answer **does not depend on height**. The linear potential is only valid near the ground (W4L1, slide 17). In real dust storms, the field near the ground can be much stronger than $E_0$, so far less charge is needed. +## 3. Earth's magnetic field +Far from a compact current system, its magnetic field is that of a dipole (W4L2, slides 14–15). Earth's main field is modelled as a dipole at Earth's centre. As in the lecture, let $\hat m=\hat z$, let $\theta$ be the angle measured from $\hat m$, and work in the $x$–$z$ plane with $\hat r=\sin\theta\,\hat x+\cos\theta\,\hat z$ (slide 22). The field is +```{math} +\vec B = B_*\left(\frac{R}{r}\right)^3\left[3(\hat m\cdot\hat r)\,\hat r-\hat m\right], +\qquad B_*=\frac{\mu_0|\vec m|}{4\pi R^3}. +``` +For Earth, take $R=a=6371\ \mathrm{km}$ and $B_*\approx 29.7\ \mu\mathrm{T}$ (called $B_0$ in the teachbook section *Earth as a Magnetic Dipole*). For the present polarity, $\hat m$ points toward the **southern** end of the dipole axis: $\theta=0$ is the southern end, $\theta=\pi$ the northern end, and $\theta=\pi/2$ the dipole equator. + +Written in the local directions $\hat r$ (outward) and $\hat\theta$ (tangent to the surface, in the direction of increasing $\theta$), the same field is +```{math} +\frac{\vec B}{B_*} = \left(\frac{R}{r}\right)^3\left(2\cos\theta\,\hat r + \sin\theta\,\hat\theta\right), +\qquad\text{that is}\qquad +B_r = 2B_*\left(\frac{R}{r}\right)^3\cos\theta, +\quad +B_\theta = B_*\left(\frac{R}{r}\right)^3\sin\theta . +``` +You may use either form. + +```{figure} figures/earth_dipole_setup.png +:width: 45% + +Geometry of the dipole model, as in W4L2, slides 17 and 22: $\hat m=\hat z$ points up the page, $\theta$ is measured from $\hat m$, and the grey arrows show $\hat r$ at the points used in (a) and (b). The dashed circle is Earth's surface, $r=a$. +``` + +(a) At the surface, $r=a$, find $\vec B/B_*$ at $\theta=0$ and $\pi/2$, and give $|\vec B|$ in $\mu\mathrm{T}$. At each point, determine whether $\vec B$ points into the Earth, out of the Earth or is tangent to the Earth's surface. Using $B_r\propto\cos\theta$, in which hemisphere does the field enter Earth? + +**(a)** At $r=a$ the factor $(R/r)^3$ equals 1. +- $\theta=0$: $\hat r=\hat z$, $\hat m\cdot\hat r=1$, so $\vec B/B_*=3\hat z-\hat z=2\hat z=2\hat r$. The field points **out of the ground**, with $|\vec B|=2B_*=\boxed{59.4\ \mu\mathrm{T}}$. +- $\theta=\pi/2$: $\hat r=\hat x$, $\hat m\cdot\hat r=0$, so $\vec B/B_*=-\hat z$. The field is **along the ground** (horizontal), pointing from the southern toward the northern end of the axis, with $|\vec B|=B_*=\boxed{29.7\ \mu\mathrm{T}}$. +Since $B_r=2B_*\cos\theta$, the radial component is positive (outward) for $\theta<\pi/2$ and negative (inward) for $\theta>\pi/2$. The field therefore leaves Earth in the southern hemisphere and **enters Earth in the northern hemisphere**; at $\theta=\pi$ it is $2\hat z=-2\hat r$, the mirror image of $\theta=0$. The field at the poles is twice as strong as at the equator (W4L2, slide 17). + +(b) At $r=a$ and $\theta=3\pi/4$ (dipole latitude $45^\circ$ N), construct $\vec B/B_*$ head to tail from $3(\hat m\cdot\hat r)\hat r$ and $-\hat m$ (W4L2, slide 16). Find $|\vec B|$ in $\mu\mathrm{T}$ and the angle between $\vec B$ and the local horizontal. *Hint:* use $\vec B\cdot\hat r=|\vec B|\cos\alpha$, where $\alpha$ is the angle between $\vec B$ and $\hat r$. The local horizontal is perpendicular to $\hat r$, so the angle between $\vec B$ and the horizontal is $|90^\circ-\alpha|$. + +**(b)** At $\theta=3\pi/4$: $\hat r=\tfrac{1}{\sqrt2}(\hat x-\hat z)$ and $\hat m\cdot\hat r=\cos\tfrac{3\pi}{4}=-\tfrac{1}{\sqrt2}$. Then +```{math} +3(\hat m\cdot\hat r)\hat r=-\tfrac32(\hat x-\hat z)=-\tfrac32\hat x+\tfrac32\hat z, +\qquad +\frac{\vec B}{B_*}=-\tfrac32\hat x+\tfrac32\hat z-\hat z=\boxed{-\tfrac32\hat x+\tfrac12\hat z}. +``` +This is the $\theta=3\pi/4$ arrow of the slide 22 practice. Its magnitude equals that of the slide 16 example: +```{math} +|\vec B|=B_*\sqrt{\tfrac94+\tfrac14}=1.58\,B_*=\boxed{47.0\ \mu\mathrm{T}}. +``` +For the direction, $\vec B\cdot\hat r=B_*\tfrac{1}{\sqrt2}\left(-\tfrac32-\tfrac12\right)=-\sqrt2\,B_*$, so +```{math} +\cos\alpha=\frac{-\sqrt2}{1.58}=-0.894,\qquad \alpha=153.4^\circ. +``` +Because $\hat r$ points outward, $\alpha>90^\circ$ already tells us that the radial component is inward: the field points **into the ground**, as it must in the northern hemisphere by part (a). + +$\hat r$ is the local vertical, so an angle measured from $\hat r$ and an angle measured from the local horizontal are complements. The field therefore lies +```{math} +|90^\circ-153.4^\circ|=\boxed{63.4^\circ} +``` +below the horizontal. Note that $\tan I=|B_r|/B_\theta=2\tan\lambda_m$: at dipole latitude $45^\circ$ it is the *tangent* of the inclination that is doubled, not the angle. That relation is derived in lab exercise 3(e). + +The component form gives the same result in one step: $B_r/B_*=2\cos\tfrac{3\pi}{4}=-\sqrt2$ and $B_\theta/B_*=\sin\tfrac{3\pi}{4}=\tfrac{1}{\sqrt2}$, so $|\vec B|=B_*\sqrt{2+\tfrac12}=1.58\,B_*$ and $\tan I=|B_r|/B_\theta=2$, i.e. $I=63.4^\circ$ below the horizontal. + +```{figure} figures/earth_dipole_vectors_solution.png +:width: 95% + +Left: $\vec B/B_*$ at the points of (a) and (b), together with the northern end, drawn with one arrow scale (compare W4L2, slide 17). Right: the head-to-tail construction at $\theta=3\pi/4$ (compare slide 16). The field points into the ground, $63.4^\circ$ below the local horizontal. +``` + +(c) ESA's Swarm satellites measure the Earth's magnetic field at about $450\ \mathrm{km}$ altitude. Consider a point directly above the location in (b), i.e. at the same dipole latitude. What happens to the magnitude $|\vec B|$ and direction of $\vec B$? + +**(c)** The bracket depends only on directions; the distance enters only through $(R/r)^3$ (W4L2, slide 15). With $r=6371+450=6821\ \mathrm{km}$, +```{math} +|\vec B|=47.0\ \mu\mathrm{T}\times\left(\frac{6371}{6821}\right)^3=47.0\times0.815=\boxed{38.3\ \mu\mathrm{T}}. +``` +The **direction does not change**: at the same $\theta$, $\hat r$ and the bracket are the same. + +(d) Above the northern end of the dipole axis, at what distance from Earth's centre has the magnetic field magnitude $|\vec B|$ decreased to $1\%$ of its value at Earth's surface ? + +**(d)** Along the axis, $|\vec B|=2B_*(a/r)^3$, so the ratio to the surface value is $(a/r)^3$: +```{math} +\left(\frac{a}{r}\right)^3=0.01 +\quad\Longrightarrow\quad +r=100^{1/3}a=4.64\,a\approx\boxed{2.96\cdot10^{4}\ \mathrm{km}}. +``` +Each doubling of the distance reduces the field by a factor of 8 (W4L2, slide 18), and $2^{2.2}\approx4.6$. The same distance holds at every $\theta$, because the ratio depends only on $r$. + + +## 4. A current loop as a magnetic dipole + +Far from a compact current loop, its magnetic field is that of a dipole (W4L2, slide 14). A circular loop carrying current $I$ around an area $A$ has the magnetic moment +```{math} +\vec m = IA\,\hat n, +``` +where $\hat n$ is the normal to the loop given by the right-hand rule: curl the fingers along the current, and the thumb gives $\hat n$. Use $\mu_0 = 4\pi\cdot10^{-7}\ \mathrm{T\,m/A}$. + +(a) In question 3, the magnetic field at Earth's dipole equator and surface was described by $B_*=\mu_0|\vec m|/(4\pi a^3)\approx 29.7\ \mu\mathrm{T}$, with $a=6371\ \mathrm{km}$. Find Earth's dipole moment $|\vec m|$. + +**(a)** Rearranging $B_*=\mu_0|\vec m|/(4\pi a^3)$, +```{math} +|\vec m| = \frac{4\pi a^3 B_*}{\mu_0} += \frac{4\pi (6.371\cdot 10^{6})^3 (29.7\cdot 10^{-6})}{4\pi\cdot 10^{-7}} += \boxed{7.7\cdot 10^{22}\ \mathrm{A\,m^2}}, +``` +which is the accepted value for Earth's dipole moment. + +(b) Earth's field is generated by electric currents in the liquid outer core (the geodynamo). As a size estimate, replace these currents by a single circular loop in the dipole's equatorial plane, with the radius of the outer core, $R_c = 3480\ \mathrm{km}$. What current $I$ is needed? Seen from above the northern end of the dipole axis, does the current circulate clockwise or counterclockwise? *Hint:* Use the right-hand rule: point your right thumb in the direction of $\hat m$, toward the southern end of Earth's dipole axis. Your curled fingers show the direction of the current. + +**(b)** The loop area is $A=\pi R_c^2=\pi(3.48\cdot 10^{6})^2=3.81\cdot 10^{13}\ \mathrm{m^2}$, so +```{math} +I = \frac{|\vec m|}{A} = \frac{7.68\cdot 10^{22}}{3.81\cdot 10^{13}} += \boxed{2.0\cdot 10^{9}\ \mathrm{A}} \approx 2\ \mathrm{GA}. +``` +$\hat m$ points toward the **southern** end of the dipole axis (question 3). Pointing the right thumb that way, the fingers curl so that the current runs **clockwise seen from above the northern end** of the axis. + +Two billion amperes is enormous for a single wire, but the geodynamo is a broad, distributed flow of conducting liquid iron, not one loop. The estimate gives the right order of magnitude for the total circulating current. + +(c) A geophysicist lays out a circular wire loop of radius $R_L = 50\ \mathrm{m}$ on flat ground and drives a current $I = 10\ \mathrm{A}$ through it. Find its magnetic moment. On the axis of the loop, at height $z$ above its centre, the exact field is (you do not need to derive it) +```{math} +B_\mathrm{loop}(z) = \frac{\mu_0 I R_L^2}{2\left(R_L^2+z^2\right)^{3/2}}. +``` +Starting from the exact loop field, show that when $z \gg R_L$, the field reduces to the dipole field on the axis $B_\mathrm{dip}(z)=\dfrac{\mu_0|\vec m|}{2\pi z^3}$ (corresponding to $\theta=0$ case of question 3). + +**(c)** The moment of the field loop is +```{math} +|\vec m| = IA = I\pi R_L^2 = (10)\pi(50)^2 = \boxed{7.9\cdot 10^{4}\ \mathrm{A\,m^2}}. +``` +Factor $z^3$ out of the exact expression: +```{math} +B_\mathrm{loop}(z) = \frac{\mu_0 I R_L^2}{2\left(R_L^2+z^2\right)^{3/2}} += \frac{\mu_0 I R_L^2}{2z^3\left(1+R_L^2/z^2\right)^{3/2}}. +``` +For $z \gg R_L$ the bracket tends to 1, and writing $I R_L^2 = |\vec m|/\pi$, +```{math} +B_\mathrm{loop} \to \frac{\mu_0 I R_L^2}{2z^3} = \boxed{\frac{\mu_0|\vec m|}{2\pi z^3} = B_\mathrm{dip}(z)}, +``` +the on-axis dipole field, which is the $\theta=0$ case of question 3. The loop only looks like a dipole from far enough away that its size no longer matters. + +(d) Find $B_\mathrm{loop}$ and $B_\mathrm{dip}$ in nT at $z = 100\ \mathrm{m}$ $(=2R_L)$ and at $z = 250\ \mathrm{m}$ $(=5R_L)$. By how many percent does the dipole formula overestimate the field at each height? Based on these results, for what approximate values of $ z/R_L $ does the dipole approximation become reasonably accurate? *Hint:* $B_\mathrm{dip}/B_\mathrm{loop} = \left(1+R_L^2/z^2\right)^{3/2}$. + +**(d)** Using the two expressions directly: + +| $z$ | $z/R_L$ | $B_\mathrm{loop}$ | $B_\mathrm{dip}$ | overestimate | +|---|---|---|---|---| +| $100\ \mathrm{m}$ | 2 | $11.2\ \mathrm{nT}$ | $15.7\ \mathrm{nT}$ | $40\%$ | +| $250\ \mathrm{m}$ | 5 | $0.95\ \mathrm{nT}$ | $1.01\ \mathrm{nT}$ | $6\%$ | + +The hint gives the error directly, since +```{math} +\frac{B_\mathrm{dip}}{B_\mathrm{loop}} = \left(1+\frac{R_L^2}{z^2}\right)^{3/2} +\approx 1 + \frac{3}{2}\frac{R_L^2}{z^2} \quad (z \gg R_L), +``` +so the overestimate falls off as $(R_L/z)^2$: $40\%$ at $z/R_L=2$, $6\%$ at $5$, $1.5\%$ at $10$ and $0.4\%$ at $20$. The dipole formula is therefore **reasonably accurate for $z/R_L \gtrsim 5$**, and good to about a percent for $z/R_L \gtrsim 10$. The same rule of thumb is why Earth's field is well described by a dipole at satellite altitude, but not close to the core. diff --git a/book/3_diffusion_fields/em_diffusion.md b/book/3_diffusion_fields/em_diffusion.md new file mode 100644 index 0000000..26e3532 --- /dev/null +++ b/book/3_diffusion_fields/em_diffusion.md @@ -0,0 +1,415 @@ +# Electromagnetic diffusive field equations with a source + +Maxwell's equations are given by + +$$ +-\nabla\times\boldsymbol H + \varepsilon\,\partial_t\boldsymbol E + \sigma\boldsymbol E = -\boldsymbol J^e, +$$ (eq:hrel) + +$$ +\nabla\times\boldsymbol E + \mu\,\partial_t\boldsymbol H = \boldsymbol 0, +$$ (eq:erel) + +where the right-hand sides contain the sources that generate the electromagnetic field. In {eq}`eq:hrel`, the source is the electric current dipole $\boldsymbol J^e$ (A/m$^2$), and in {eq}`eq:erel` the source is zero, because no magnetic monopoles have been found. Some electric sources can be approximated by a magnetic current dipole source. A closed current-carrying loop antenna is such an electric current source that is often described as a magnetic dipole, which can be understood from integrating both sides of {eq}`eq:erel` over the area of the loop, performing a scalar product of each term with the unit normal to the loop, and using Stokes' theorem on the curl of the electric field. In the left-hand sides, $\boldsymbol E$ and $\boldsymbol H$ are the electric and magnetic field strengths in V/m and A/m, respectively, and the medium parameters $\varepsilon,\sigma,\mu$ are the electric permittivity and conductivity, and the magnetic permeability, with units of s/($\Omega$m), 1/($\Omega$m), and s$\Omega$/m, respectively. These equations describe in principle the electric, magnetic and electromagnetic fields for all possible time variations, including the static fields discussed before. Here we are interested in the diffusive field regime. + +:::{admonition} A new bridge to wave fields to distinguish them from diffusive fields +:class: important + +We see that {eq}`eq:hrel` is Ampère's law modified by Maxwell contains both the electric field and the time derivative of the electric field. We take the divergence of this equation and obtain + +$$ +(\sigma + \varepsilon\,\partial_t)\,\nabla\cdot\boldsymbol E = -\nabla\cdot\boldsymbol J^e . +$$ + +If we use the fact the $\boldsymbol D=\varepsilon\boldsymbol E$ and that $\nabla\cdot\boldsymbol D=\rho_f$ with $\rho_f$ being the volume density of free charge (C m$^{-3}$). Substituting this in the equation gives + +$$ +\partial_t\rho_f = -\nabla\cdot(\sigma\boldsymbol E + \boldsymbol J^e). +$$ + +You have seen this equation without the external source term in the section on 'Steady Currents, Charge Conservation, and a Bridge to Waves'. This is known as the equation of continuity of electric current, or the charge conservation law. Here we continue the bridge to waves and by assuming there is an accumulation of free charge of $\rho_0$ at $t=0$. We remove the source and replace it with the initial condition that $\rho_f(0)=\rho_0$. We write the electric field as $\boldsymbol E=\boldsymbol D/\varepsilon$, and find + +$$ +\partial_t\rho_f = -\frac{\sigma}{\varepsilon}\rho_f, +$$ + +the solution of which is known as + +$$ +\rho_f = \rho_0\exp\left(-\frac{\sigma}{\varepsilon}t\right) = \rho_0\exp(-t/\tau_r), +$$ + +with $\tau_r=\varepsilon/\sigma$ is known as the charge relaxation time and it is a measure of the time it takes the medium to return to its equilibrium state after it has been disturbed by an electromagnetic wave. First, we learn from this equation the following theorem: + +**_Within a region of non-vanishing conductivity there can be no permanent distribution of free charge_**. + +This is the significant equation, because when alternating source currents have oscillation periods much larger than the relaxation time, the effect of $\varepsilon$ can be neglected and we can effectively assume $\varepsilon=0$ in the first Maxwell equation. For all Earth materials, $\varepsilon < 10^{-9}$ F/m and $\sigma\gtrsim 10^{-4}$ S/m for most earth materials under investigation the relaxation time is less than 10 $\mu$s. Hence, for source time function oscillations with periods less than 0.3 $\mu$s, the electromagnetic field will be a wave field, whereas for source time function oscillations with periods longer than 0.3 ms, we can safely take $\varepsilon=0$. Electromagnetic waves are treated later in the course. +::: + +We write Maxwell's equations in the diffusive approximation out in components as, + +$$ +\begin{aligned} +-\partial_y H_z + \partial_z H_y + \sigma E_x &= -J_x^e, \\ +-\partial_z H_x + \partial_x H_z + \sigma E_y &= -J_y^e, \\ +-\partial_x H_y + \partial_y H_x + \sigma E_z &= -J_z^e, +\end{aligned} +$$ + +$$ +\begin{aligned} +\partial_y E_z - \partial_z E_y + \mu\,\partial_t H_x &= 0, \\ +\partial_z E_x - \partial_x E_z + \mu\,\partial_t H_y &= 0, \\ +\partial_x E_y - \partial_y E_x + \mu\,\partial_t H_z &= 0 . +\end{aligned} +$$ + +First we link these equations to the 1D heat equation by assuming a one-dimensional problem here as well. + +## Maxwell's equations in one dimension with a source + +If the source is an infinite current sheet with a constant current in the $(x,y)$-plane and the medium parameters $\sigma$ and $\mu$ are constant, it means that all fields are independent of the $x$- and $y$-coordinates and the derivatives $\partial_x$ and $\partial_y$ become zero. Then, when the current has an $x$-component only, we have $J_y^e=J_z^e=0$. We substitute these findings in the equations and find + +$$ +\begin{aligned} +\partial_z H_y + \sigma E_x &= -J_x^e, \\ +-\partial_z H_x + \sigma E_y &= 0, \\ +\sigma E_z &= 0, \\ +-\partial_z E_y + \mu\,\partial_t H_x &= 0, \\ +\partial_z E_x + \mu\,\partial_t H_y &= 0, \\ +\mu\,\partial_t H_z &= 0, +\end{aligned} +$$ + +which eliminates the vertical electric and magnetic field components and results in two equal but independent sets of two coupled differential equations, one for $E_x,H_y$ and one for $E_y,H_x$, but the latter has no source to generate the fields and without a generating source, they will be zero. This leads to equations for $E_x$ and $H_y$, as + +$$ +\partial_z H_y(z,t) + \sigma E_x(z,t) = -J_x^e(z,t), +$$ (eq:plzHy) + +$$ +\partial_z E_x(z,t) + \mu\,\partial_t H_y(z,t) = 0 . +$$ + +The diffusive field that satisfies this equation is called the Transverse ElectroMagnetic (TEM) diffusive field, because both the electric and magnetic fields are transverse (perpendicular) to the propagation direction. The diffusion equation for the electric field is obtained by eliminating the magnetic field from the two equations above. We do that as follows, we multiply both sides of {eq}`eq:plzHy` with $\mu$ and apply a time derivative, which leads to, + +$$ +\partial_z\left(\mu\,\partial_t H_y(z,t)\right) + \sigma\mu\,\partial_t E_x(z,t) = -\mu\,\partial_t J_x^e(z,t), +$$ (eq:plzpltHy) + +$$ +\mu\,\partial_t H_y(z,t) = -\partial_z E_x(z,t). +$$ (eq:pltHy) + +We then substitute the right-hand side of the {eq}`eq:pltHy` to replace the term with the magnetic field in {eq}`eq:plzpltHy`, we find that the electric field satisfies the following diffusion equation: + +$$ +\partial_z\partial_z E_x - \mu\sigma\,\partial_t E_x = \mu\,\partial_t J_x^e(z,t). +$$ (eq:dee) + +{eq}`eq:dee` has the same structure as the heat equation. We now have the electric field instead of temperature and the heat conductivity $\kappa$ has been replaced by $\sigma\mu$, which is the electromagnetic diffusion coefficient and it has units of s/m$^2$, and there is a source term in the right-hand side. + +To construct the solution for this equation, we assume the source is active in an arbitrary space-time interval, given by $J_x^e(z,t)\ne0$ for $z_bz'$. We can assume the strength of these two fields are equal and we can propose a solution of the form, + +$$ +\hat G = \hat A\left\{\exp\left[-\sqrt{\mathrm{i}\omega\mu\sigma}\,(z-z')\right]u(z-z') + \exp\left[\sqrt{\mathrm{i}\omega\mu\sigma}\,(z-z')\right]u(z'-z)\right\}. +$$ + +where $\hat A$ is the constant that needs to be determined. The field must diffuse away from the source and decrease in amplitude with increasing distances in both the positive and negative $z$-directions, as depicted in {numref}`fig-greens1d`. This is in contrast with finite domains where we have to impose end point conditions and signals travelling in both directions can occur everywhere on the line segment. Here the fields travel only in one direction and we use physics to tell us that the field should go to zero when we move infinitely far away from the source. Evaluating the first and second derivatives with respect to $z$ gives + +```{figure} figures/Greens1D.png +:name: fig-greens1d +:width: 70% + +The generated of signals by a point source on the line at $z=z'$ with a signal that propagates in the positive and in the negative $z$-directions away from the location $z=z'$. +``` + +$$ +\begin{aligned} +\partial_z\hat G &= -\sqrt{\mathrm{i}\omega\sigma\mu}\,\hat A\left\{\exp\left[-\sqrt{\mathrm{i}\omega\mu\sigma}\,(z-z')\right]u(z-z') - \exp\left[\sqrt{\mathrm{i}\omega\mu\sigma}\,(z-z')\right]u(z'-z)\right\}, \\ +\partial_z\partial_z\hat G &= \mathrm{i}\omega\mu\sigma\hat A\exp\left(-\sqrt{\mathrm{i}\omega\sigma\mu}\,|z-z'|\right) - 2\sqrt{\mathrm{i}\omega\sigma\mu}\,\hat A\,\delta(z-z')\exp\left(-\sqrt{\mathrm{i}\omega\sigma\mu}\,|z-z'|\right) \\ +&= \mathrm{i}\omega\sigma\mu\hat G - 2\sqrt{\mathrm{i}\omega\sigma\mu}\,\hat A\,\delta(z-z'), +\end{aligned} +$$ + +where we used the fact that + +$$ +\partial_z u[\pm(z-z')] = \pm\delta(z-z') +$$ + +and the terms with those derivatives cancel in the expression of the first derivative, whereas in the second derivative they add up. We have used the fact that we can combine the two solutions as + +$$ +\exp\left(-\sqrt{\mathrm{i}\omega\sigma\mu}\,|z-z'|\right) = \exp\left[-\sqrt{\mathrm{i}\omega\mu\sigma}\,(z-z')\right]u(z-z') + \exp\left[\sqrt{\mathrm{i}\omega\mu\sigma}\,(z-z')\right]u(z'-z). +$$ + +If we substitute these results in {eq}`eq:deegs` we find that + +$$ +\hat A = \frac{\exp(-\mathrm{i}\omega t')}{2\sqrt{\mathrm{i}\omega\sigma\mu}}, +$$ + +and the Green's function is then + +$$ +\hat G = \frac{\exp\left(-\sqrt{\mathrm{i}\omega\sigma\mu}\,|z-z'|\right)}{2\sqrt{\mathrm{i}\omega\sigma\mu}}\exp(-\mathrm{i}\omega t'). +$$ + +The space-time Green's function is obtained by the inverse Fourier transformation, which is known but beyond the scope of the course. It is given by + +$$ +G(z-z',t-t') = \sqrt{\frac{1}{4\pi\sigma\mu(t-t')}}\exp\left(-\frac{\sigma\mu(z-z')^2}{4(t-t')}\right), \quad\text{for } t>t'. +$$ + +The source is taken as $J_x^e(z,t)=I\delta(z)u(t)$, which represents the plane electric current sheet in the $(x,y)$-plane at $z=0$ with a current $I$ directed along the $x$-axis and with a step switch-on time function $u(t)$. This means it is an impulse in the $z$-direction and of infinite extent in the $x$- and $y$-directions. The switch-on current source means $I$ is a constant for all times after $t=0$, $u(t)=0$ for $t<0$ and $u(t)=1$ for $t>0$. For this source, the integrals in {eq}`eq:EGJ` can be evaluated explicitly and the electric field is given by + +$$ +E_x(z,t) = -I\sqrt{\frac{\mu}{4\pi\sigma t}}\exp\left(-\frac{\sigma\mu z^2}{4t}\right), \quad\text{for } t>0 . +$$ (eq:ExtH) + +You recognise the similarity with the solution to the heat equation with a Gaussian distribution for the initial temperature on an infinitely long wire. Note that here we make explicit that the expression for the electric field exists only for positive times. This is because $t=0$ is the moment the source is switched on and physics tells us that the Earth will respond to a source action only at or after the moment the source becomes active and not before. This is the notion of causality. + +## Maxwell's equations in two dimensions with a source + +If the source is an infinitely long wire and with a constant current in the $z$-direction, and the medium parameters are constants, all fields are independent of the $z$-coordinate and the derivative $\partial_z$ becomes zero, and $J_x^e=J_y^e=0$. With these choices, Maxwell's equations become + +$$ +\begin{aligned} +-\partial_y H_z + \sigma E_x &= 0, \\ +\partial_x H_z + \sigma E_y &= 0, \\ +-\partial_x H_y + \partial_y H_x + \sigma E_z &= -J_z^e, \\ +\partial_y E_z + \mu\,\partial_t H_x &= 0, \\ +-\partial_x E_z + \mu\,\partial_t H_y &= 0, \\ +\partial_x E_y - \partial_y E_x + \mu\,\partial_t H_z &= 0 . +\end{aligned} +$$ + +The fields that connect to the source are grouped as + +$$ +-\partial_x H_y + \partial_y H_x + \sigma E_z = -J_z^e, +$$ (eq:TEEy) + +$$ +\mu\,\partial_t H_x = -\partial_y E_z, +$$ (eq:TEHx) + +$$ +\mu\,\partial_t H_y = \partial_x E_z. +$$ (eq:TEHz) + +Because the fields do not depend on the $z$-direction, the plane of interest is the $(x,y)$-plane. We see that the electric field is perpendicular to the plane where the fields will change while the magnetic field has a direction in that plane. For this reason this is called the Transverse Electric or TE mode. We use {eq}`eq:TEHx` and {eq}`eq:TEHz` to substitute the magnetic fields in {eq}`eq:TEEy` to find the differential equation that $E_z$ satisfies, + +$$ +(\partial_x^2 + \partial_y^2 - \sigma\mu\,\partial_t)E_z = \mu\,\partial_t J_z^e. +$$ + +We recognise that the equation is very similar to the equation in one dimension. We can also see that the two magnetic field components satisfy + +$$ +\begin{aligned} +(\partial_x^2 + \partial_y^2 - \sigma\mu\,\partial_t)H_x &= -\partial_y J_z^e, \\ +(\partial_x^2 + \partial_y^2 - \sigma\mu\,\partial_t)H_y &= \partial_x J_z^e. +\end{aligned} +$$ + +We are not going to derive solutions but give the electric and magnetic fields for a current $I$ that is switched on at $t=0$ and remains constant after that, + +$$ +\begin{aligned} +E_z(x,y,t) &= -\frac{\mu I}{4\pi t}\exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right), \\ +H_x(x,y,t) &= -\frac{\mu y I}{2\pi\varrho^2}\exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right), \\ +H_y(x,y,t) &= \frac{\mu x I}{2\pi\varrho^2}\exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right). +\end{aligned} +$$ + +The expressions are in Cartesian coordinates, but we use $\varrho=\sqrt{x^2+y^2}$ for horizontal distance. First, we observe that the electric field will go to zero inversely proportional to time, while the magnetic field components will increase to its static value. In the section about the curl-operator, an expression was given for the static magnetic field of an infinitely long vertical electric wire in Cartesian coordinates in {eq}`eq:HJcyl`. There, we assumed the current was switched on infinitely long ago. We could then show that the static magnetic field is curl-free at any point outside the wire, while {eq}`eq:TEEy` shows that as long as the magnetic field is diffusive, its curl is not zero. In the Introduction to Potential Fields, it was given in cylindrical coordinates. Here we see that the electric and magnetic field have transient behaviour that is the result of switching the current on in the wire. The electric field vanishes while the magnetic field becomes a constant at infinite time. This means that towards infinite time, the magnetic field becomes a potential field. A final note is that the conductivity of the medium determines how fast the electric field vanishes and the magnetic field attains its final value but that the final magnetic field strength does not depend on the conductivity of the medium. The behaviour of the electric field as a function of time is shown in {numref}`fig-ezt` for three different distances to the wire. The conductivity of the medium is $\sigma=3$ S/m, which is a good value to mimic the value in seawater. + +```{figure} figures/Ezt.png +:name: fig-ezt +:width: 70% + +The vertical electric field strength as a function of time for three distances to the infinitely long wire. +``` + +The figure shows the curves at 0.36 m (black line), 15 m (red line) and 30 m (dashed blue line) distances to the wire. Very close to the wire the electric field is already fully established at 0.1 ms and only shows it is inversely proportional to time, which is shown by the black line. For increasing distances to the wire, the field is initially small, then rises exponentially and at some time after its peak value it will show behaviour that inversely proportional to time. The time to the maximum value is obtained as $t_p=\sigma\mu\varrho^2/4$. This means the electric field reaches its maximum value at $t_p=0.21$ ms at 15 m distance and at $t_p=0.84$ ms at 30 m distance. Once the field becomes inversely proportional to time, all values are the same and the field goes uniformly to zero. The magnetic field can be analysed as well. The equations show that they both have the exponential function that governs the time behaviour. We take the zeroth- and first-order terms of the Taylor series expansion of the exponential function in the expression of the magnetic field for large time and find + +$$ +\exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right) = 1 - \frac{\sigma\mu\varrho^2}{4t} + \mathcal{O}(t^{-2}). +$$ + +When it would be 1, the magnetic field would have its static value. The second term shows how far away from the static value the magnetic field is. That is the behaviour to analyse. We plot these functions for two different distances. We can see that their difference from the static value will have asymptotic behaviour inversely proportional to time for large values of time, $t\gg\sigma\mu\varrho^2/4$. {numref}`fig-hxt` shows + +$$ +H_x(x,y,t) - H_x(x,y,t\rightarrow\infty) = \frac{\mu y I}{2\pi\varrho^2}\left[1 - \exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right)\right], +$$ + +for a constant $y$-value of $y=0.25$ m and two radial distances of 15 m (red line) and 30 m (dashed blue line) to the wire together with its asymptotic value proportional to inverse time (black line). Hence, for constant $y$, $H_x$ depends only on $t$ for $t\gg\sigma\mu\varrho^2/4$. We conclude that the magnetic field approaches its static value in exactly the same way the electric field vanishes! This is true for the $y$-component of the magnetic field as well and hence for the total magnetic field magnitude. + +```{figure} figures/Hxt.png +:name: fig-hxt +:width: 70% + +The $x$-component of the magnetic field strength minus its static value as a function of time for a fixed $y$-value of $y=0.25$ m and two distances to the infinitely long wire. +``` + +## Maxwell's equations in three dimensions with a source + +If we return to the Maxwell equations and find the scalar three-dimensional second order differential equation and replace the right-hand side with a three-dimensional delta-function, we end up with the diffusion equation for the Green's function in three dimensions. The derivation is beyond the scope of this course, but we will work with the Green's function. The Green's function satisfies, + +$$ +(\nabla^2 - \mathrm{i}\omega\sigma\mu)\,\hat G = -\delta(\boldsymbol r-\boldsymbol r'), +$$ + +and the frequency domain Green's function is given by + +$$ +\hat G(\boldsymbol r-\boldsymbol r',\omega) = \frac{\exp\left(-\sqrt{\mathrm{i}\omega\sigma\mu}\,|\boldsymbol r-\boldsymbol r'|\right)}{4\pi|\boldsymbol r-\boldsymbol r'|} . +$$ + +The space-time domain Green's function is + +$$ +G(\boldsymbol r-\boldsymbol r',t-t') = \frac{(\sigma\mu)^{1/2}}{[4\pi(t-t')]^{3/2}}\exp\left(-\frac{\sigma\mu|\boldsymbol r-\boldsymbol r'|^2}{4(t-t')}\right), \quad\text{for } t>t', +$$ (eq:G3D) + +and it satisfies + +$$ +(\nabla^2 - \sigma\mu\,\partial_t)\,G = -\delta(\boldsymbol r-\boldsymbol r')\,\delta(t-t') . +$$ + +Again we recognise the similarity with solution for the heat equation for an infinitely long wire with an initial temperature that was a Gaussian distribution. It also resembles the 1D and 2D diffusive field solution to Maxwell's equations. The major difference is that here the late-time behaviour is proportional to $t^{-3/2}$. The electric and magnetic field have much more complicated behaviour but that is beyond the scope of the present course. In case of an electric current loop source the electric field can be written in the same way as for the infinitely long wire, but now we must integrate along the wire segments of the loop. The reason is that the electric field generated by a loop source is divergence-free. + +### Brief analysis of the outcome + +For a source in the location $\boldsymbol r'$, the field diffuses away in spherical direction and the amplitude only depends on radial distance. The product $\sigma\mu$ is the diffusion constant and has the unit of s/m$^2$. It is a measure of how fast the width of the Gaussian spreads in space for a given time instant. + +**Early time behaviour.** The early-time behaviour is similar to what we saw in the 1D heat equation. + +**Late time behaviour.** The late-time behaviour is inversely proportional to $t^{3/2}$, which is faster than what we saw in the solutions to the 1D heat and Maxwell diffusion equations. + +**Time to the peak.** If we differentiate the Green's function to $t$ and equate the result to zero, we find the time to the peak to be $t-t'=t_p$, at $t_p=\sigma\mu|\boldsymbol r-\boldsymbol r'|^2/6$. The amplitude of the Green's function at the peak time is given by + +$$ +G(\boldsymbol r-\boldsymbol r',t-t'=t_p) = \frac{3\sqrt{6}\exp(-3/2)}{4\pi^{3/2}\sigma\mu|\boldsymbol r-\boldsymbol r'|^3}, +$$ + +which shows that if you double the distance to the source, the peak amplitude is 8 times smaller. + +## The diffusive electric field generated by an electric loop source + +In the field, a loop is often used to generate a transient electromagnetic field and the Earth response is recorded at the ground surface with an electric field antenna or with a loop receiver. Loops are also carried in the air by a helicopter or a drone, in which case either the same loop, or another smaller loop is used to measure the time derivative of the magnetic induction in the Earth response. Here we look at the electric field that is generated in a conductive medium by a rectangular loop as indicated in {numref}`fig-loop`, with sides $L_x$ and $L_y$ and a unit amplitude step switch-on source time function. The current runs clockwise from the vertices labeled 1 to 4. The coordinates of these vertices are given by + +$$ +\begin{aligned} +\boldsymbol r_1 &= (-L_x/2,-L_y/2,0), & \boldsymbol r_2 &= (L_x/2,-L_y/2,0),\\ +\boldsymbol r_3 &= (L_x/2,L_y/2,0), & \boldsymbol r_4 &= (-L_x/2,L_y/2,0). +\end{aligned} +$$ + +The point of observation is $\boldsymbol r$. For a loop source, the electric field is divergence-free and we can write the electric field as a convolution of the Green's function and the source vector, given by + +$$ +\boldsymbol E(\boldsymbol r,t) = -\mu\oint_{\boldsymbol r'\in L} G(\boldsymbol r-\boldsymbol r',t)\,\boldsymbol\tau(\boldsymbol r')\,\mathrm{d}l, +$$ + +which is a line integral along the four line segments of the loop. The unit vector $\boldsymbol\tau$ is equal to $\hat{\boldsymbol x}$ when we integrate from $\boldsymbol r_1$ to $\boldsymbol r_2$ and it is $-\hat{\boldsymbol x}$ when we integrate from $\boldsymbol r_3$ to $\boldsymbol r_4$. Similarly, the unit vector $\boldsymbol\tau$ is equal to $\hat{\boldsymbol y}$ when we integrate from $\boldsymbol r_2$ to $\boldsymbol r_3$ and it is $-\hat{\boldsymbol y}$ when we integrate from $\boldsymbol r_4$ to $\boldsymbol r_1$. We can therefore write the two horizontal components of the electric field as + +$$ +\begin{aligned} +E_x(\boldsymbol r,t) &= -\frac{\mu}{4\pi}\sqrt{\frac{\sigma\mu}{4\pi t^3}}\left\{\exp\left(-\frac{\sigma\mu[(y+L_y/2)^2+z^2]}{4t}\right) - \exp\left(-\frac{\sigma\mu[(y-L_y/2)^2+z^2]}{4t}\right)\right\} \\ +&\quad\times\int_{-L_x/2}^{L_x/2}\exp\left(-\frac{\sigma\mu(x-x')^2}{4t}\right)\mathrm{d}x', +\end{aligned} +$$ + +$$ +\begin{aligned} +E_y(\boldsymbol r,t) &= -\frac{\mu}{4\pi}\sqrt{\frac{\sigma\mu}{4\pi t^3}}\left\{\exp\left(-\frac{\sigma\mu[(x-L_x/2)^2+z^2]}{4t}\right) - \exp\left(-\frac{\sigma\mu[(x+L_x/2)^2+z^2]}{4t}\right)\right\} \\ +&\quad\times\int_{-L_y/2}^{L_y/2}\exp\left(-\frac{\sigma\mu(y-y')^2}{4t}\right)\mathrm{d}y', +\end{aligned} +$$ + +```{figure} figures/Loopsrc.png +:name: fig-loop +:width: 80% + +An electric current square loop source with a unit step switch-on current and its vertices 1, 2, 3, and 4. +``` + +where the exponentials with argument $y\pm L_y/2$ represent the integrals from point $\boldsymbol r_2$ to $\boldsymbol r_3$ and from $\boldsymbol r_4$ to $\boldsymbol r_1$, respectively. Because the integrals are similar but just run over a different coordinate axis, we will carry out the integral in the $x$-direction and then we write down the solution for the integral in $y$-direction by substitution. In the integral, we substitute $p=\sqrt{\sigma\mu(x-x')^2/(4t)}$ and integrate over the new variable $p$. The Jacobian of the parameter transformation is $\mathrm{d}p=\sqrt{\sigma\mu/(4t)}\,\mathrm{d}x'$. + +$$ +\int_{-L_x/2}^{L_x/2}\exp\left(-\frac{\sigma\mu(x-x')^2}{4t}\right)\mathrm{d}x' = \sqrt{\frac{4t}{\sigma\mu}}\int_{\sqrt{\frac{\sigma\mu}{4t}}x_m}^{\sqrt{\frac{\sigma\mu}{4t}}x_p}\exp(-p^2)\,\mathrm{d}p, +$$ + +where the new coordinates are introduced as $x_m=x-L_x/2$ and $x_p=x+L_x/2$. This is also a good moment to introduce the diffusion distance as + +$$ +D = \sqrt{\frac{4t}{\sigma\mu}}. +$$ + +Independent from whether $x\pm L_x/2>0$ or $x\pm L_x/2<0$, we can always write the integral as a difference of two integrals that both start at $p=0$, + +$$ +\int_{Dx_m}^{Dx_p}\exp(-p^2)\,\mathrm{d}p = \int_{0}^{Dx_p}\exp(-p^2)\,\mathrm{d}p - \int_{0}^{Dx_m}\exp(-p^2)\,\mathrm{d}p = \frac{\sqrt{\pi}}{2}\left[\mathrm{erf}(Dx_p) - \mathrm{erf}(Dx_m)\right], +$$ + +where $\mathrm{erf}$ denotes the error function and the scale factor is chosen such that $\mathrm{erf}(\infty)=1$. Substituting these results in the expressions for the electric field, we finally obtain + +$$ +E_x(\boldsymbol r,t) = -\frac{\mu}{8\pi t}\left\{\exp\left(-\frac{y_p^2+z^2}{D^2}\right) - \exp\left(-\frac{y_m^2+z^2}{D^2}\right)\right\}\left[\mathrm{erf}\left(\frac{x_p}{D}\right) - \mathrm{erf}\left(\frac{x_m}{D}\right)\right], +$$ (eq:Exloop) + +$$ +E_y(\boldsymbol r,t) = -\frac{\mu}{8\pi t}\left\{\exp\left(-\frac{x_m^2+z^2}{D^2}\right) - \exp\left(-\frac{x_p^2+z^2}{D^2}\right)\right\}\left[\mathrm{erf}\left(\frac{y_p}{D}\right) - \mathrm{erf}\left(\frac{y_m}{D}\right)\right]. +$$ (eq:Eyloop) + +{eq}`eq:Exloop` and {eq}`eq:Eyloop` are the expressions for the electric field anywhere in space and for all times after the source has been switched on. They show that $E_x=0$ in the $(x,z)$-plane at $y=0$ because then $y_p^2=y_m^2$ and $E_y=0$ in the $(y,z)$-plane at $x=0$ because then $x_p^2=x_m^2$. That makes sense because the contributions from the two line-segments in the $x$-direction have equal distance to all the points in the $(x,z)$ plane but have opposite currents. The equations also show that $E_y$ is the strongest in the $(x,z)$-plane at $y=0$ because then $y_p=-y_m$ and the error functions add up, and similarly $E_x$ is strongest in the $(y,z)$-plane at $x=0$ because then $x_p=-x_m$. The electric field is computed for a square loop with 100 m long segments placed in a conductive medium with $\sigma=0.3$ S/m. The result can be seen in {numref}`fig-et12xz` where $E_y$ is shown for two time instances in the $(x,z)$-plane at $y=0$, which is the cross-section right through the middle of the loop, such that the wire segments between points 4 and 1 and points 2 and 3 are perpendicular to the plane of the graph. The figure shows $E_y$ as a function of $x$ and $z$ at $t=0.03$ ms (left plot) and $t=5$ ms (right plot). It is shown only for positive depth values, but the field is symmetric in $z$ and the plot can be mirrored to add the picture of negative $z$. It can be seen that at 0.03 ms, the field is very strong and concentrated around the wires of the loop, whereas at 5 ms, the field is three orders of magnitude weaker and it almost occupies all the plane where the plot is made. Hence, we see that the maximum value of the electric field moves away from the loop wire segments and the width of the Gaussian in space widens with increasing time. + +```{figure} figures/Eyt_xz.png +:name: fig-et12xz +:width: 100% + +The electric field $E_y$ generated by a unit step switch-on current in the $(x,z)$-plane at $y=0$ m, for times $0.03$ ms (left plot) and $5$ ms (right plot). +``` + +At very early times and not too far away from the loop in the $z$-direction, the electric field shows the shape of the loop but the vector points in the opposite direction of the current vector in the loop. This can be seen in {numref}`fig-et12xy` where the magnitude of the electric field vector is shown in colour in the $(x,y)$-plane at $z=10$ m, at $t=0.03$ ms (left plot) and $t=5$ ms (right plot) and the white arrows show the direction of the electric field. At $t=0.03$ ms, the left plot shows that far away from the line segments, the electric field is fully aligned with but points in opposite direction as the current direction in the line segments, but the amplitude is very small. Curvature of the field lines going around the loop can be seen closer to the loop and is again almost fully aligned with the line segments just above them, but also here the field points in the opposite direction as the source current. At the later time of 5 ms, the right plot shows that the shape of the source loop is lost and the electric field is almost circular inside and around the loop. Notice also that the field strength has decreased by three orders of magnitude, the same factor as in the $(x,z)$-plane. Once the diffusion distance $D$ exceeds the size of the loop, the error function bracket goes as $L_y/D$ and the difference of exponentials as $2xL_x/D^2$, so away from the symmetry axes the field falls off as $t^{-5/2}$ at every position. The rate is a property of the diffusion, not of the direction we look in. + +```{figure} figures/Eyt_xy.png +:name: fig-et12xy +:width: 100% + +The magnitude $|\boldsymbol E|$ of the electric field generated by a unit step switch-on current in the $(x,y)$-plane at $z=10$ m, for times $0.03$ ms (left plot) and $5$ ms (right plot). The white arrows give the direction of the field. +``` diff --git a/book/3_diffusion_fields/figures/Eyt_xy.png b/book/3_diffusion_fields/figures/Eyt_xy.png new file mode 100644 index 0000000..36f061b Binary files /dev/null and b/book/3_diffusion_fields/figures/Eyt_xy.png differ diff --git a/book/3_diffusion_fields/figures/Eyt_xz.png b/book/3_diffusion_fields/figures/Eyt_xz.png new file mode 100644 index 0000000..41be021 Binary files /dev/null and b/book/3_diffusion_fields/figures/Eyt_xz.png differ diff --git a/book/3_diffusion_fields/figures/Ezt.png b/book/3_diffusion_fields/figures/Ezt.png new file mode 100644 index 0000000..85f21d9 Binary files /dev/null and b/book/3_diffusion_fields/figures/Ezt.png differ diff --git a/book/3_diffusion_fields/figures/GHeat.png b/book/3_diffusion_fields/figures/GHeat.png new file mode 100644 index 0000000..b648c93 Binary files /dev/null and b/book/3_diffusion_fields/figures/GHeat.png differ diff --git a/book/3_diffusion_fields/figures/GHeatA.png b/book/3_diffusion_fields/figures/GHeatA.png new file mode 100644 index 0000000..e1a2d9c Binary files /dev/null and b/book/3_diffusion_fields/figures/GHeatA.png differ diff --git a/book/3_diffusion_fields/figures/Greens1D.png b/book/3_diffusion_fields/figures/Greens1D.png new file mode 100644 index 0000000..e54ab81 Binary files /dev/null and b/book/3_diffusion_fields/figures/Greens1D.png differ diff --git a/book/3_diffusion_fields/figures/Hxt.png b/book/3_diffusion_fields/figures/Hxt.png new file mode 100644 index 0000000..a135420 Binary files /dev/null and b/book/3_diffusion_fields/figures/Hxt.png differ diff --git a/book/3_diffusion_fields/figures/Loopsrc.png b/book/3_diffusion_fields/figures/Loopsrc.png new file mode 100644 index 0000000..4124511 Binary files /dev/null and b/book/3_diffusion_fields/figures/Loopsrc.png differ diff --git a/book/3_diffusion_fields/figures/heat_ic_quarters.svg b/book/3_diffusion_fields/figures/heat_ic_quarters.svg new file mode 100644 index 0000000..a800540 --- /dev/null +++ b/book/3_diffusion_fields/figures/heat_ic_quarters.svg @@ -0,0 +1,426 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/3_diffusion_fields/figures/heat_ic_thirds.svg b/book/3_diffusion_fields/figures/heat_ic_thirds.svg new file mode 100644 index 0000000..c4742c2 --- /dev/null +++ b/book/3_diffusion_fields/figures/heat_ic_thirds.svg @@ -0,0 +1,388 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/3_diffusion_fields/figures/make_figures.py b/book/3_diffusion_fields/figures/make_figures.py new file mode 100644 index 0000000..6f21438 --- /dev/null +++ b/book/3_diffusion_fields/figures/make_figures.py @@ -0,0 +1,43 @@ +"""Regenerate the initial-condition sketches of the heat-equation exercises. + +Run from this directory: python make_figures.py +""" +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt + +INK = "#6b7280" # neutral grey, readable on light and dark backgrounds +LINE = "#00A6D6" # TU Delft cyan + +def step_sketch(fname, edges, values, xticks, xticklabels): + fig, ax = plt.subplots(figsize=(4.2, 2.4)) + xs, ys = [], [] + for (a, b), v in zip(zip(edges[:-1], edges[1:]), values): + xs += [a, b] + ys += [v, v] + ax.plot(xs, ys, color=LINE, lw=2) + ax.axhline(0, color=INK, lw=0.8) + ax.set_xlim(-0.05, 1.12) + ax.set_ylim(-1.35, 1.35) + ax.set_xticks(xticks, xticklabels) + ax.set_yticks([-1, 0, 1]) + ax.set_xlabel("$x$", color=INK) + ax.set_ylabel("$h(x)$", color=INK) + for side in ("top", "right"): + ax.spines[side].set_visible(False) + for side in ("left", "bottom"): + ax.spines[side].set_color(INK) + ax.tick_params(colors=INK) + fig.tight_layout() + fig.savefig(fname, transparent=True, metadata={"Date": None}) + plt.close(fig) + +# exercise 4: h = 0, -1, 1, 0 on the four quarters of the bar, T(0,t) = T(L,t) = 0 +step_sketch("heat_ic_quarters.svg", + [0, 0.25, 0.5, 0.75, 1.0], [0, -1, 1, 0], + [0, 0.25, 0.5, 0.75, 1.0], ["0", "$L/4$", "$L/2$", "$3L/4$", "$L$"]) + +# exercise 5: h = 1, -1, 1 on the three thirds of the bar, insulated ends +step_sketch("heat_ic_thirds.svg", + [0, 1/3, 2/3, 1.0], [1, -1, 1], + [0, 1/3, 2/3, 1.0], ["0", "$L/3$", "$2L/3$", "$L$"]) diff --git a/book/3_diffusion_fields/heat_equation_1d.md b/book/3_diffusion_fields/heat_equation_1d.md new file mode 100644 index 0000000..2f81481 --- /dev/null +++ b/book/3_diffusion_fields/heat_equation_1d.md @@ -0,0 +1,533 @@ +# The heat equation in one dimension + +Let us assume the heat can flow only in the $x$-direction, like in a bar. This reduces the heat equation, {eq}`eq:Heat`, to + +$$ +\partial_t T - \kappa\,\partial_x^2 T = 0, +$$ (eq:Heat1D) + +where we assume no source or sink is present, for which reason the right-hand side is zero. If we want to find a solution to this equation, we will need other information. These are initial conditions and boundary conditions. The number of conditions needed is equal to the highest order derivative in a variable. {eq}`eq:Heat1D` has a first-order time derivative, which means we need one initial or boundary condition, and it has a second-order spatial derivative, which means we need two initial or boundary conditions in space. Let us assume the bar has length $L$ and extends from $x=0$ to $x=L$. So-called Dirichlet conditions describe the temperature at the end points, $x=0$ and $x=L$, e.g., $T(0,t)=0$ and $T(L,t)=0$. So-called Neumann conditions prescribe the normal component of the current, or, in this case, the first spatial derivative of temperature. For example, a no-flow end-point condition for an insulated bar, meaning no heat can flow away from the bar, is expressed as + +$$ +\begin{aligned} +\partial_x T(0,t) &= 0, \\ +\partial_x T(L,t) &= 0. +\end{aligned} +$$ + +For some source-free problems, solutions can be found using the technique of separation of variables. This means that we can write the temperature in the bar as a product of a function that depends only on position and a function that depends only on time. We are going to find a solution for two different cases. + +## Example 1: bar with zero temperature at the end points + +For such a bar we use the 1D heat equation with conditions on the temperature at the end points, + +$$ +\begin{aligned} +\partial_t T &= \kappa\,\partial_x^2 T, \\ +T(x,0) &= h(x), \\ +T(0,t) &= 0, \\ +T(L,t) &= 0. +\end{aligned} +$$ + +Note that the boundary condition at zero time is an arbitrary function $h(x)$ of position. This condition allows for non-trivial solutions and this means that the function $h(x)$ can be seen as the starting point of the diffusive process. We could see it as equivalent to the presence of a source. The boundary conditions do not depend on time and space simultaneously and we can try a solution with separation of variables. We take a solution in the form + +$$ +T(x,t) = f(x)\,g(t), +$$ + +and put it in the equation to find + +$$ +\begin{aligned} +\partial_t\left[f(x)g(t)\right] &= \kappa\,\partial_x^2\left[f(x)g(t)\right], \\ +f(x)\,\partial_t g(t) &= \kappa\,g(t)\,\partial_x^2 f(x), \\ +\frac{\partial_t g(t)}{g(t)} &= \kappa\frac{\partial_x^2 f(x)}{f(x)} = -\kappa\lambda . +\end{aligned} +$$ + +The separation constant $\lambda$ is introduced to be able to separate the two equations and solve them independently. Note that attaching $\kappa$ to the separation constant is not required but convenient. If you don't do it, it does not matter. When you discover in a later step that it would be better to do it, you can come back here and do it after all. We can now write the equation as two equations, + +$$ +\begin{aligned} +\partial_t g(t) &= -\kappa\lambda\,g(t), \\ +\partial_x^2 f(x) &= -\lambda\,f(x). +\end{aligned} +$$ + +Now, we must find out if we can satisfy the boundary conditions for $T(x,t)$ and move them to conditions for $f(x)$ and $g(t)$. We find + +$$ +T(0,t) = f(0)g(t) = 0 \quad\text{and}\quad T(L,t) = f(L)g(t) = 0 . +$$ + +If we would choose $g(t)=0$ then we would find the trivial solution that the temperature is zero everywhere and for all times. Hence, we choose $f(0)=f(L)=0$ as boundary conditions for $f(x)$. The separation constant $\lambda$ is known as the eigenvalue of the problem. We are going to find that non-trivial solutions are found only for specific values of $\lambda$. The non-trivial solution for a value of $\lambda$ is then called an eigenfunction. You have encountered or will encounter this in the course ECTB2130, Signals and Time Series. An eigenfunction of a differential equation is a function that, when it is taken as an input signal, gives as output the same function scaled by a factor, which is then the corresponding eigenvalue. + +Now we are ready to solve the corresponding two equations, + +$$ +\begin{aligned} +(\partial_t + \kappa\lambda)\,g &= 0, \\ +(\partial_x^2 + \lambda)\,f &= 0, \\ +f(0) = f(L) &= 0 . +\end{aligned} +$$ + +In fact, we solve first the spatial equation. We must consider three ranges for $\lambda$ to find solutions for the second-order differential equation. + +**Case $\lambda>0$.** For positive eigenvalues, the solution consists of oscillating functions, + +$$ +f(x) = c_1\sin(x\sqrt{\lambda}) + c_2\cos(x\sqrt{\lambda}). +$$ (eq:fsincosd) + +Because $f(0)=0$, we find $c_2=0$. Because $f(L)=0$, we find that $\sin(L\sqrt{\lambda})=0$, which leads to + +$$ +\lambda = \left(\frac{n\pi}{L}\right)^2, \quad\text{for } n=1,2,3,\cdots, +$$ + +hence the solution is given by + +$$ +f(x) = c_1\sin\left(\frac{n\pi x}{L}\right), \quad\text{for } n=1,2,3,\cdots . +$$ + +There is an infinite number of eigenvalues, each of which has its own eigenfunction as solution to the problem. Note that $c_1$ is not determined by this condition and we could remove it, because later we will need to make sure to satisfy the last condition of $T(x,0)=h(x)$. For simplicity we keep it here as an undetermined constant. + +**Case $\lambda=0$.** For a zero eigenvalue, the solution is given by $f(x)=c_0+c_1x$. Because both $f(0)$ and $f(L)$ must be zero, we find that both coefficients are zero and only the trivial solution exists. Hence $f(x)=0$. This also means that $\lambda=0$ is not an eigenvalue for this problem! + +**Case $\lambda<0$.** For negative eigenvalues, the solution consists of exponential functions given by + +$$ +f(x) = c_1\exp(x\sqrt{-\lambda}) + c_2\exp(-x\sqrt{-\lambda}). +$$ + +Setting $f(0)=0$ and $f(L)=0$ leads again to $c_1=0$ and $c_2=0$. We see that for negative values of $\lambda$ only the trivial solution is found. Hence, also no negative eigenvalues exist for this problem. + +Now it is time to solve the time equation. We must consider only positive values of $\lambda$ and substitute $\lambda_n$ that we can later specify as found above. For each value of $\lambda_n$, we should find a solution $g_n(t)$. The corresponding equation is written as + +$$ +(\partial_t + \kappa\lambda_n)\,g_n = 0 . +$$ + +This is a simple first-order equation and we know that exponential functions are repeated when differentiated. Hence, we find the solution to be of the form + +$$ +g_n(t) = c_n\exp(-\kappa\lambda_n t) = c_n\exp\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right]. +$$ + +The temperature is given by the product of the two solutions. We can write for every $n$, + +$$ +T_n(x,t) = C_n\sin\left(\frac{n\pi x}{L}\right)\exp\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right]. +$$ (eq:T1Dn) + +The coefficient $C_n$ combines the coefficients we found in the solution in space and in time. Note that this is a solution, but that does not mean that this function alone can satisfy all boundary conditions we can think of. The function $h(x)$ of the boundary condition at zero time is an arbitrary function of position. This means that the solution is quite restrictive and can be used only for functions $h(x)$ that match $T_n(x,0)$. We are of course allowed to combine solutions for different values of $n$, because the problem is linear and the principle of superposition applies. This means we can write the temperature as a solution to the heat equation as + +$$ +T(x,t) = \sum_{n=1}^{\infty} C_n\sin\left(\frac{n\pi x}{L}\right)\exp\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right], +$$ + +with initial condition + +$$ +T(x,0) = h(x) = \sum_{n=1}^{\infty} C_n\sin\left(\frac{n\pi x}{L}\right). +$$ (eq:BCheat1D) + +With an infinite sum of functions, we can imagine we can satisfy almost all functions $h(x)$. Now the question is: How can we find the coefficients $C_n$ such that {eq}`eq:BCheat1D` is satisfied? That is not very difficult. We see that the argument of the sine-function is at least spanning half a period for $00$.** For positive eigenvalues, the solution consists of oscillating functions, + +$$ +f(x) = c_1\sin(x\sqrt{\lambda}) + c_2\cos(x\sqrt{\lambda}). +$$ (eq:fsincosn) + +Because $f'(0)=0$, we find $\left.\partial_x f(x)\right|_{x=0} = c_1\sqrt{\lambda} = 0$, hence $c_1=0$. Because $f'(L)=0$, we find that $c_2\sqrt{\lambda}\sin(L\sqrt{\lambda})=0$, which leads to + +$$ +\lambda = \left(\frac{n\pi}{L}\right)^2, \quad\text{for } n=1,2,3,\cdots, +$$ + +hence the solution is given by + +$$ +f_n(x) = c_2\cos\left(\frac{n\pi x}{L}\right), \quad\text{for } n=1,2,\cdots . +$$ + +There is an infinite number of eigenvalues, each of which has its own eigenfunction as solution to the problem. + +**Case $\lambda=0$.** For a zero eigenvalue, the solution is given by $f(x)=c_0+c_1x$. Because both $f'(0)$ and $f'(L)$ must be zero, we find that the coefficient $c_1=0$ and only the solution $f(x)=c_0$ exists for $\lambda=0$. This means that $\lambda=0$ is an eigenvalue for this problem! + +**Case $\lambda<0$.** For negative eigenvalues, the solution consists of exponential functions given by + +$$ +f(x) = c_1\exp(x\sqrt{-\lambda}) + c_2\exp(-x\sqrt{-\lambda}). +$$ + +To impose $f'(0)=0$ and $f'(L)=0$ we need + +$$ +f'(x) = \sqrt{-\lambda}\left[c_1\exp(x\sqrt{-\lambda}) - c_2\exp(-x\sqrt{-\lambda})\right]. +$$ + +This leads from $f'(0)=0$ to $c_1=c_2$, and from $f'(L)=0$ we find $c_1=c_2=0$. Hence, there are no negative eigenvalues for this problem. + +The total solution so far is + +$$ +f_n(x) = c_2\cos\left(\frac{n\pi x}{L}\right), \quad\text{for } n=0,1,2,\cdots . +$$ + +Now it is time to solve the time equation. We recognise that this part of the problem is the same as before and we find the solution to be of the form + +$$ +g_n(t) = c_n\exp\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right]. +$$ + +The temperature is given by the product of the two solutions. We can write for every $n$ + +$$ +T_n(x,t) = C_n\cos\left(\frac{n\pi x}{L}\right)\exp\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right], \quad n=0,1,2,\cdots . +$$ (eq:T1Dnc) + +Note that $n=0$ is now part of the solution. The temperature as a solution to the heat equation is the sum of all solutions $T_n$ and given by + +$$ +T(x,t) = \sum_{n=0}^{\infty} C_n\cos\left(\frac{n\pi x}{L}\right)\exp\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right], +$$ + +with initial condition + +$$ +T(x,0) = h(x) = \sum_{n=0}^{\infty} C_n\cos\left(\frac{n\pi x}{L}\right). +$$ + +What we found for Fourier sine-series in the previous example applies to the Fourier cosine-series as well. Applying Fourier orthogonality of cosine-functions results in the final solution + +$$ +\begin{aligned} +T(x,t) &= \sum_{n=0}^{\infty} C_n\cos\left(\frac{n\pi x}{L}\right)\exp\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right], \\ +C_n &= \left\{\begin{array}{ll} +\dfrac{1}{L}\displaystyle\int_{x=0}^{L} h(x)\,\mathrm{d}x, & n=0, \\[3mm] +\dfrac{2}{L}\displaystyle\int_{x=0}^{L} h(x)\cos\left(\frac{n\pi x}{L}\right)\mathrm{d}x, & n=1,2,3,\cdots . +\end{array}\right. +\end{aligned} +$$ + +With these two expressions, we have fully solved a partial differential equation with Neumann boundary conditions. Note that now the temperature does not necessarily go to zero when time goes to infinity. + +## A completely different solution procedure + +### An infinitely long wire with an initial Gaussian temperature distribution + +Solving problems with separation of variables is not always the best solution, e.g., when the temperature distribution at $t=0$ is a Gaussian function. For this example, we assume an infinitely long wire. Hence, we are solving + +$$ +\begin{aligned} +\partial_t T &= \kappa\,\partial_x^2 T, \\ +T(x,0) &= T_0\exp\left(-\frac{x^2}{L^2}\right). +\end{aligned} +$$ (eq:c0time) + +Note that we do not use explicit boundary conditions at the end points, but are satisfied with zero conditions, which seems to make sense from a physical point of view. We can see from the initial condition of {eq}`eq:c0time` that + +$$ +\lim_{x\rightarrow\pm\infty} T(x,t) = 0 . +$$ (eq:endcond) + +The boundary condition at zero time shows that at $x=0$ and $t=0$ the temperature is $T_0$, which is the peak value of the temperature. The constant $L$ in the Gaussian is a measure of the width of the Gaussian function. The actual peak value may change and the width of the Gaussian may change, but we assume that the solution will have a Gaussian structure in space, and we are going to find what its time behaviour then is. Let us propose a solution of the form + +$$ +T(x,t) = f(t)\exp\left(-h(t)x^2\right). +$$ + +The two functions $f(t)$ and $h(t)$ allow for time variations in peak temperature and the time at which the peak occurs. Note that this solution cannot be easily written as a product of a time-dependent function and a space-dependent function as we did in the method of separation of variables. For $h(t)\ge 0$, the temperature will exponentially decrease with increasing $x$. Because we introduce two new time functions that we want to find, we need boundary conditions for them. We can find them from the boundary condition on $T(x,0)$ as + +$$ +f(0) = T_0, \qquad h(0) = \frac{1}{L^2} . +$$ (eq:initchf) + +We substitute the proposed solution in {eq}`eq:Heat1D` and find + +$$ +\begin{aligned} +\exp\left(-h(t)x^2\right)\left[\partial_t f(t) - x^2 f(t)\,\partial_t h(t)\right] &= \kappa\left[4f(t)h^2(t)x^2 - 2f(t)h(t)\right]\exp\left(-h(t)x^2\right), \\ +\partial_t f(t) + 2\kappa f(t)h(t) &= x^2\left[f(t)\,\partial_t h(t) + 4\kappa f(t)h^2(t)\right]. +\end{aligned} +$$ + +Similar to the solution with separation of variables, here we see that the left-hand side of the equation constitutes an equation that can be solved independent from $x$, and the right-hand side does depend on the location. Hence the whole equation can be satisfied for all values of $x$ only when the left-hand side is satisfied independently from the right-hand side and vice versa. We find the following two differential equations, + +$$ +\partial_t f(t) = -2\kappa f(t)h(t), +$$ (eq:eqhf) + +$$ +\partial_t h(t) = -4\kappa h^2(t). +$$ (eq:eqhh) + +The first equation depends on both $f(t)$ and $h(t)$ and must be solved after we solve the equation for $h(t)$. It is not hard to show that + +$$ +h(t) = \frac{1}{4\kappa t + L^2} +$$ + +is a solution to {eq}`eq:eqhh` that satisfies the initial condition of {eq}`eq:initchf` as well. Similarly, it is then not hard to show that + +$$ +f(t) = T_0\frac{L}{\sqrt{4\kappa t + L^2}} +$$ + +satisfies {eq}`eq:eqhf` and satisfies the initial condition of {eq}`eq:initchf`. This solves the problem and we find the temperature along the bar as a function of time as + +$$ +T(x,t) = \frac{T_0 L}{\sqrt{4\kappa t + L^2}}\exp\left(-\frac{x^2}{4\kappa t + L^2}\right). +$$ (eq:TGauss) + +Notice that we have solved the heat equation using the initial condition for $T(x,0)$ at zero time expressed in {eq}`eq:c0time` and end-point conditions at infinity for all times expressed in {eq}`eq:endcond`. We found a solution in terms of a single expression using ordinary functions. It is clear that this problem cannot be easily solved with the method of separation of variables. In the exercises, we find a solution in terms of the Fourier cosine series. The explicit exact solution that we found here gives a better insight in the space-time behaviour of diffusive fields than the solution with separation of variables, and can be analysed. + +### Analysis of the outcome + +**Early time behaviour.** We can see that for zero time, the solution is well behaved, because the square root in time in the denominator goes to $L$ when time goes to zero and the temperature goes to $T_0$ as given as the initial value. If we think about the origin of this heat, it must have come from some negative time, and we can imagine it must have come from time equal to $t=-L^2/(4\kappa)$. In that case the denominator goes to zero and the polynomial term will blow up to infinity. But we can see that for $x\ne 0$, the exponential function has the time in the denominator of its argument and that will bring the temperature to zero at $t=-L^2/(4\kappa)$. The only problematic point is then $x=0$, which must be the location of the origin of the heat. This is characteristic for solutions to the diffusive field equation with a source that is approximated to be localised in a single point. Note that all finite order derivatives to time of this function go to zero at zero time. Another way of saying this is: an exponential function with a negative argument that is inversely proportional to time goes to zero faster than a polynomial of any finite inverse power of time goes to infinity for zero time. Notice that for times $t<-L^2/(4\kappa)$ the solution is no longer physical. The reason is that the square root in the polynomial term will have a negative argument and the outcome of such a square root will be complex, which we regard as non-physical in space-time. You can see that + +$$ +\begin{aligned} +\lim_{t\uparrow -\frac{L^2}{4\kappa}}\exp\left(-\frac{x^2}{4\kappa t + L^2}\right) &= \infty, \\ +\lim_{t\rightarrow -\infty}\exp\left(-\frac{x^2}{4\kappa t + L^2}\right) &= 1, +\end{aligned} +$$ + +from which we conclude that negative infinite time is not a problem for the exponential term, but the negative side of the zero denominator in the exponential function is the problem. In addition, we can see that for any fixed time $t<-L^2/(4\kappa)$ the exponential function is no longer well-behaved as a function of $x$ and grows exponentially for increasing distance. That is a second reason to regard solutions for $t<-L^2/(4\kappa)$ as non-physical. + +**Late time behaviour.** The late-time behaviour is entirely determined by the polynomial function, and hence we conclude that the temperature drops proportional to the inverse square root of time and does not depend on location anymore! The reason is that when $t\rightarrow\infty$, $\exp\left[-x^2/(4\kappa t + L^2)\right]\rightarrow 1$ for any fixed position. Hence, the exponential function is a Gaussian in space, but as a function of time it is zero at zero time and it smoothly goes to 1 at infinite time. Hence, for late times, the exponential function has no more influence on the value of the temperature in the bar. + +**Time to the peak temperature.** We can compute how much time it takes for the temperature to reach its peak value at any point on the bar. To determine the time to the peak value, we take the derivative to time and equate the result to zero. The derivative to time of {eq}`eq:TGauss` is given by + +$$ +\begin{aligned} +\partial_t T(x,t) &= \exp\left(-\frac{x^2}{4\kappa t + L^2}\right)\partial_t\frac{T_0 L}{\sqrt{4\kappa t + L^2}} ++ \frac{T_0 L}{\sqrt{4\kappa t + L^2}}\,\partial_t\exp\left(-\frac{x^2}{4\kappa t + L^2}\right), \\ +&= -\frac{2\kappa T_0 L}{(4\kappa t + L^2)^{3/2}}\exp\left(-\frac{x^2}{4\kappa t + L^2}\right) ++ \frac{4\kappa T_0 L x^2}{(4\kappa t + L^2)^{5/2}}\exp\left(-\frac{x^2}{4\kappa t + L^2}\right). +\end{aligned} +$$ + +This derivative is zero when time is equal to the time to the peak, $t_p$, and this is given by + +$$ +t_p = \frac{2x^2 - L^2}{4\kappa}, +$$ + +from which it is clear that only for $|x|>L/\sqrt{2}$ this happens at positive times. That means that for points on the bar where $|x|L/\sqrt{2}$ the temperature will first rise for $0L/\sqrt{2} . +$$ + +We conclude that the temperature has a maximum value that is inversely proportional to distance $|x|$, and it occurs on the bar for positions $|x|>L/\sqrt{2}$. + +To show the early- and late-time behaviour, we show the temperature as a function of time. In the example, $T_0=1$, $\kappa=1$, $L=10$, and we compute the temperature for positions $-30L/\sqrt{2}\approx 7$ m occurs at later times with increasing distance to the mid point. The time of the maximum temperature value grows with distance squared. This is not very well visible in the plot, because of the logarithmic time scale. + +```{figure} figures/GHeat.png +:name: fig-gheat +:width: 75% + +The temperature as a function of space and time with a Gaussian distribution in space at $t=0$ as initial condition. +``` + +Looking at the temperature as a function of time for specific locations away from the mid point is useful to evaluate the interplay between the late-time, or polynomial, part and the early-time, or exponential, part. To this end, {numref}`fig-gheata` shows them as a function of time for distances of $x=10$ m (left plot) and $x=20$ m (right plot) as black curves, together with the polynomial part (red dashed lines) and the exponential part (blue dashed lines). The vertical thin black lines mark the time to the maximum temperature, which is 25 s for $x=10$ m and 175 s for $x=20$ m. + +```{figure} figures/GHeatA.png +:name: fig-gheata +:width: 100% + +The temperature as a function of time at $x=10$ m (left) and $x=20$ m (right), with a Gaussian distribution in space at $t=0$ as initial condition. The black curve is the temperature, the red dashed line the polynomial part, the blue dashed line the exponential part, and the thin vertical line marks the time $t_p$ to the maximum temperature. +``` + +### An infinitely long wire with an initial double Gaussian temperature distribution + +If the initial condition specifies two shifted Gaussians, the solution can be written immediately by understanding that the superposition principle holds. This means that two separate initial conditions each lead to a solution that can be summed and that is equal to the solution we would obtain by specifying the two initial conditions as a single starting point and then solving the equation. Hence, if we have + +$$ +\begin{aligned} +\partial_t T &= \kappa\,\partial_x^2 T, \\ +T(x,0) &= T_0\left[\exp\left(-\frac{(x+2L)^2}{L^2}\right) + \exp\left(-\frac{(x-2L)^2}{L^2}\right)\right], +\end{aligned} +$$ (eq:2c0time) + +the solution can be readily given by + +$$ +T(x,t) = \frac{T_0 L}{\sqrt{4\kappa t + L^2}}\left[\exp\left(-\frac{(x+2L)^2}{4\kappa t + L^2}\right) + \exp\left(-\frac{(x-2L)^2}{4\kappa t + L^2}\right)\right]. +$$ (eq:T2Gauss) + +From this solution, and the fact that the exponential functions are quite distinct for early times but become equal for late times, we can understand that after some time we cannot distinguish between a field that consisted initially of two Gaussians and one that consisted of a single Gaussian temperature distribution. The closer the initial peak values are together, the earlier the blurring is such that the distinction cannot be made anymore. In a nutshell, that is the difficulty with analysing diffusive field signals when we record them to obtain information about the Earth. + +## The infinitely long wire revisited: a solution with the Fourier cosine series + +Solving problems with separation of variables is not always the best solution, for example when the temperature distribution at $t=0$ is a Gaussian function, but it is possible and can still be convenient. For the example, we return to the infinitely long wire. Hence, we are solving the same equation and boundary condition as before, + +$$ +\begin{aligned} +\partial_t T &= \kappa\,\partial_x^2 T, \\ +T(x,0) &= T_0\exp\left(-\frac{x^2}{L^2}\right). +\end{aligned} +$$ + +This function goes to zero at the end points "infinity", which seems to make sense from a physical point of view. We still want a solution of the form + +$$ +T(x,t) = f(x)g(t). +$$ + +We cannot use the boundary conditions at "infinity", because that would not help us in finding eigenvalues. Instead we can look at the functional description of the boundary condition at zero time. This is a Gaussian function in space and it is characterised by the width $L$. Hence the fact that the wire is infinitely long does not matter too much, because the temperature goes exponentially to zero for large distances. We can then choose a finite length $M$ and we will approximate the boundary condition with $2M$ as the length of the wire. + +The initial distribution is an even function in space. This means that an integral $-\infty0)$ or sink $(S<0)$, and substitution of Fourier's law in this equation gives + +$$ +\partial_t T - \kappa\nabla^2 T = S, +$$ (eq:Heat) + +where we have assumed constant heat conductivity. This is called a scalar diffusive field, or parabolic, equation, because in all source- and sink-free regions, a first-order time derivative of temperature is equal to a second-order spatial derivative of temperature. This is a general expression for a diffusion equation in three-dimensional space and time. A similar equation exists for other fields, for non-scalar fields as well, and we look at the electromagnetic field diffusion later. We first look at the heat equation in one and three dimensions. diff --git a/book/3_diffusion_fields/labs/figures/ELoopwsxz.mp4 b/book/3_diffusion_fields/labs/figures/ELoopwsxz.mp4 new file mode 100644 index 0000000..75c8522 Binary files /dev/null and b/book/3_diffusion_fields/labs/figures/ELoopwsxz.mp4 differ diff --git a/book/3_diffusion_fields/labs/figures/bar_boundary_conditions.svg b/book/3_diffusion_fields/labs/figures/bar_boundary_conditions.svg new file mode 100644 index 0000000..fed5034 --- /dev/null +++ b/book/3_diffusion_fields/labs/figures/bar_boundary_conditions.svg @@ -0,0 +1,1031 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/3_diffusion_fields/labs/figures/make_figures.py b/book/3_diffusion_fields/labs/figures/make_figures.py new file mode 100644 index 0000000..c4feb72 --- /dev/null +++ b/book/3_diffusion_fields/labs/figures/make_figures.py @@ -0,0 +1,43 @@ +"""Regenerate the schematic of the diffusive-fields lab. Run: python make_figures.py""" +import matplotlib +matplotlib.use("Agg") +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle, FancyArrowPatch + +INK, BAR, RES, OUT = "#6b7280", "#8a9199", "#00A6D6", "#EC6842" + + +def bar(ax, y, label): + ax.add_patch(Rectangle((0, y - 0.18), 1, 0.36, fc=BAR, ec=INK, alpha=0.35, lw=1)) + ax.text(0.5, y + 0.3, label, ha="center", va="bottom", color=INK, fontsize=10) + + +def arrow(ax, x0, x1, y): + ax.add_patch(FancyArrowPatch((x0, y), (x1, y), arrowstyle="-|>", mutation_scale=14, + color=OUT, lw=2)) + + +fig, ax = plt.subplots(figsize=(6.4, 3.0)) +# Dirichlet: ends clamped to reservoirs at the reference temperature +bar(ax, 1.25, "Example 1: $T(0,t)=T(L,t)=0$, ends held at the reference temperature") +for x0 in (-0.13, 1.0): + ax.add_patch(Rectangle((x0, 0.98), 0.13, 0.54, fc=RES, ec=RES, alpha=0.55)) +ax.text(-0.065, 0.9, "$T=0$", ha="center", va="top", color=INK, fontsize=9) +ax.text(1.065, 0.9, "$T=0$", ha="center", va="top", color=INK, fontsize=9) +arrow(ax, 0.1, -0.2, 1.25); arrow(ax, 0.9, 1.2, 1.25) +ax.text(1.24, 1.25, "heat can\nleave", ha="left", va="center", color=OUT, fontsize=8) + +# Neumann: insulated ends +bar(ax, 0.0, r"Example 2: $\partial_x T(0,t)=\partial_x T(L,t)=0$, insulated ends") +for x0 in (-0.05, 1.0): + ax.add_patch(Rectangle((x0, -0.27), 0.05, 0.54, fc="none", ec=INK, hatch="////", lw=1)) +ax.text(1.12, 0.0, "no flux", ha="left", va="center", color=INK, fontsize=8) + +ax.set_xticks([0, 1], ["$0$", "$L$"]); ax.set_yticks([]) +ax.set_xlim(-0.35, 1.45); ax.set_ylim(-0.5, 1.95) +for s in ("left", "right", "top"): + ax.spines[s].set_visible(False) +ax.spines["bottom"].set_color(INK); ax.tick_params(colors=INK) +ax.set_xlabel("$x$", color=INK) +fig.tight_layout() +fig.savefig("bar_boundary_conditions.svg", transparent=True, metadata={"Date": None}) diff --git a/book/3_diffusion_fields/labs/figures/make_week06_figures.py b/book/3_diffusion_fields/labs/figures/make_week06_figures.py new file mode 100644 index 0000000..45a98b6 --- /dev/null +++ b/book/3_diffusion_fields/labs/figures/make_week06_figures.py @@ -0,0 +1,240 @@ +"""Regenerate the four model-setup schematics of the Week 6 lab. + +Run: python make_week06_figures.py + +Same palette and conventions as make_figures.py: transparent SVG, grey ink so the +theme can invert it in dark mode, TU Delft cyan for the field under study and +orange for the source. Depth runs downward throughout, as it does on every figure +in the chapter. Long captions go in figure coordinates, so they never fight the +equal aspect ratio the circular panels need. +""" +import matplotlib +matplotlib.use("Agg") +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle, FancyArrowPatch, Circle, Polygon, Arc + +INK, GND, SRC, FLD = "#6b7280", "#8a9199", "#EC6842", "#00A6D6" + + +def arrow(ax, p0, p1, color=SRC, lw=2.0, scale=13, z=5): + ax.add_patch(FancyArrowPatch(p0, p1, arrowstyle="-|>", mutation_scale=scale, + color=color, lw=lw, zorder=z, shrinkA=0, shrinkB=0)) + + +def bare(ax, xlim, ylim, equal=False): + ax.set_xlim(*xlim); ax.set_ylim(*ylim) + ax.set_xticks([]); ax.set_yticks([]) + for s in ax.spines.values(): + s.set_visible(False) + if equal: + ax.set_aspect("equal") + + +def caption(fig, text, y=0.035, size=8.5): + fig.text(0.5, y, text, ha="center", va="bottom", color=INK, fontsize=size) + + +# --------------------------------------------------------------------------- +# Part 1: an infinite current sheet, seen edge-on +# --------------------------------------------------------------------------- +def sheet(): + fig, ax = plt.subplots(figsize=(6.8, 3.1)) + ax.add_patch(Rectangle((-1.0, -1.0), 2.0, 1.0, fc=GND, ec="none", alpha=0.16)) + ax.text(0.97, -0.96, "conductor $\\sigma,\\ \\mu$", ha="right", va="bottom", + color=INK, fontsize=9) + + # the sheet itself + ax.plot([-1.0, 1.0], [0, 0], color=SRC, lw=3, solid_capstyle="butt", zorder=4) + for x in np.linspace(-0.88, 0.72, 7): + arrow(ax, (x, 0), (x + 0.16, 0), scale=9, lw=1.3) + ax.text(0.0, 0.07, "current sheet at $z=0$: current $I$ per unit width along $x$," + " infinite in $x$ and $y$", + ha="center", va="bottom", color=SRC, fontsize=9) + + # depth axis + arrow(ax, (-1.18, 0.0), (-1.18, -0.95), color=INK, lw=1.2, scale=11) + ax.text(-1.23, -0.48, "depth $z$", ha="right", va="center", color=INK, + fontsize=9.5, rotation=90) + + # spreading front, then the three receivers + for z in np.linspace(-0.10, -0.94, 8): # the spreading front, left margin only + ax.plot([-0.97, -0.45], [z, z], color=FLD, lw=0.9, ls=":", alpha=0.55, zorder=2) + for z, lab in ((-0.22, "100 m"), (-0.45, "300 m"), (-0.82, "1000 m")): + ax.add_patch(Polygon([(-0.06, z), (0.06, z), (0.0, z + 0.055)], closed=True, + fc=FLD, ec=FLD, zorder=6)) + ax.text(0.11, z, f"receiver at {lab}", ha="left", va="center", color=FLD, + fontsize=9) + arrow(ax, (-0.36, z), (-0.11, z), color=FLD, lw=1.5, scale=10) + ax.text(-0.40, -0.22, "$E_x$", ha="right", va="center", color=FLD, fontsize=10) + + bare(ax, (-1.45, 1.35), (-1.12, 0.26)) + caption(fig, "The field diffuses downward. The solution is even in $z$, so reading $z$" + " as depth idealises away the air above.") + fig.tight_layout(rect=(0, 0.08, 1, 1)) + fig.savefig("setup_sheet.svg", transparent=True, metadata={"Date": None}) + plt.close(fig) + + +# --------------------------------------------------------------------------- +# Part 2: an infinite wire, and the plane the fields live in +# --------------------------------------------------------------------------- +def wire(): + fig, (a0, a1) = plt.subplots(1, 2, figsize=(7.4, 3.2), + gridspec_kw=dict(width_ratios=[0.85, 1.15])) + + # left: the wire, with the plane of interest cutting it + a0.plot([0, 0], [-1.1, 1.1], color=SRC, lw=3, zorder=5) + for y in (-0.8, -0.05, 0.6): + arrow(a0, (0, y), (0, y + 0.26), scale=11, lw=1.6) + a0.text(0.1, 1.05, "wire along $z$,\ncurrent $I$", ha="left", va="top", + color=SRC, fontsize=9.5) + a0.add_patch(Polygon([(-0.95, -0.38), (0.5, -0.64), (0.95, -0.02), (-0.5, 0.24)], + closed=True, fc=FLD, ec=FLD, alpha=0.20, lw=1.2, zorder=2)) + a0.text(-1.08, -0.62, "the $(x,y)$-plane", ha="left", va="top", color=FLD, + fontsize=9.5) + a0.set_title("side view", color=INK, fontsize=9.5, pad=6) + bare(a0, (-1.15, 1.35), (-1.35, 1.25)) + + # right: that plane, seen along the wire + for r in (0.34, 0.60, 0.86): + a1.add_patch(Circle((0, 0), r, fc="none", ec=FLD, lw=1.3, ls="--", alpha=0.85)) + a1.add_patch(Arc((0, 0), 1.20, 1.20, theta1=22, theta2=68, color=FLD, lw=1.9)) + th = np.deg2rad(68) + arrow(a1, (0.60 * np.cos(th), 0.60 * np.sin(th)), + (0.60 * np.cos(th + 0.22), 0.60 * np.sin(th + 0.22)), color=FLD, lw=1.9, + scale=13) + a1.text(0.34, 0.80, "$\\boldsymbol{H}$ circles the wire", ha="left", va="bottom", + color=FLD, fontsize=9.5) + + a1.add_patch(Circle((0, 0), 0.085, fc="none", ec=SRC, lw=2, zorder=6)) + a1.add_patch(Circle((0, 0), 0.026, fc=SRC, ec=SRC, zorder=6)) + a1.text(0.0, -0.14, "$I$ out, $E_z$ in", ha="center", va="top", color=SRC, fontsize=9) + + ta = np.deg2rad(-32) + arrow(a1, (0, 0), (0.86 * np.cos(ta), 0.86 * np.sin(ta)), color=INK, lw=1.3, + scale=11) + a1.text(0.50, -0.40, "$\\varrho$", ha="left", va="top", color=INK, fontsize=11) + a1.set_title("seen along the wire", color=INK, fontsize=9.5, pad=6) + bare(a1, (-1.1, 1.25), (-1.1, 1.1), equal=True) + + caption(fig, "Nothing depends on $z$, so the fields live in the $(x,y)$-plane:" + " $I$ points out of it and $E_z$ into it, $\\boldsymbol{H}$ lies in it.\n" + "Receivers sit at three distances from the wire.", y=0.02) + fig.tight_layout(rect=(0, 0.15, 1, 1)) + fig.savefig("setup_wire.svg", transparent=True, metadata={"Date": None}) + plt.close(fig) + + +# --------------------------------------------------------------------------- +# Part 3: the same kernel, spreading over a plane, a cylinder and a sphere +# --------------------------------------------------------------------------- +def ladder(): + fig, axes = plt.subplots(1, 3, figsize=(7.6, 3.0)) + titles = ("sheet, 1-D", "wire, 2-D", "point, 3-D") + pees = ("$p = 1/2$", "$p = 1$", "$p = 3/2$") + tps = ("$t_p = ?$", "$t_p = ?$", "$t_p = ?$") + spreads = ("spreads one way", "spreads over a circle", "spreads over a sphere") + + for k, ax in enumerate(axes): + if k == 0: + ax.plot([-0.85, 0.85], [0, 0], color=SRC, lw=3, zorder=5) + for z in (0.26, 0.5, 0.74): + for s in (1, -1): + ax.plot([-0.85, 0.85], [s * z, s * z], color=FLD, lw=1.2, ls="--", + alpha=0.85) + arrow(ax, (0.0, 0.0), (0.0, -0.72), color=FLD, lw=1.6) + ax.text(0.09, -0.38, "$r$", color=FLD, fontsize=11, va="center") + else: + fills = (0.0, 0.11)[k == 2] + for r, al in ((0.30, 0.9), (0.54, 0.65), (0.78, 0.4)): + if fills: + ax.add_patch(Circle((0, 0), r, fc=FLD, ec="none", alpha=fills)) + ax.add_patch(Circle((0, 0), r, fc="none", ec=FLD, lw=1.2, ls="--", + alpha=al)) + ax.add_patch(Circle((0, 0), 0.05, fc=SRC, ec=SRC, zorder=6)) + aa = np.deg2rad(38) + arrow(ax, (0, 0), (0.78 * np.cos(aa), 0.78 * np.sin(aa)), color=FLD, lw=1.6) + ax.text(0.20, 0.44, "$r$", color=FLD, fontsize=11, + ha="right", va="bottom") + + ax.set_title(titles[k], color=INK, fontsize=10.5, pad=8) + ax.text(0.0, -1.06, spreads[k], ha="center", va="top", color=INK, fontsize=8.5) + ax.text(0.0, -1.34, pees[k], ha="center", va="top", color=SRC, fontsize=11.5) + ax.text(0.0, -1.66, tps[k], ha="center", va="top", color=INK, fontsize=10.5) + bare(ax, (-1.0, 1.0), (-2.0, 1.0), equal=True) + + caption(fig, "One kernel, $\\exp(-\\sigma\\mu r^2/4t)$. Only the prefactor $t^{-p}$" + " changes. Your $t_p(r, p)$ fills in the three question marks.", y=0.025) + fig.tight_layout(rect=(0, 0.07, 1, 1)) + fig.savefig("setup_ladder.svg", transparent=True, metadata={"Date": None}) + plt.close(fig) + + +# --------------------------------------------------------------------------- +# Part 4: the loop, and the two planes the lab cuts through it +# --------------------------------------------------------------------------- +def loop(): + # axonometric projection: x right, y toward the viewer (down-left), z down + def P(x, y, z): + return (x - 0.52 * y, -0.30 * y - 0.92 * z) + + L, zc = 1.0, 0.72 # half-side, and the depth of the (x,y) cut + fig, ax = plt.subplots(figsize=(6.8, 3.6)) + + # the vertical cut at y = 0, drawn first so the rest sits on top + ax.add_patch(Polygon([P(-1.75, 0, -0.05), P(1.75, 0, -0.05), P(1.75, 0, 1.05), + P(-1.75, 0, 1.05)], closed=True, fc=FLD, ec=FLD, lw=1.0, + alpha=0.13, zorder=1)) + # the ground surface + ax.add_patch(Polygon([P(-1.9, -1.8, 0), P(1.9, -1.8, 0), P(1.9, 1.8, 0), + P(-1.9, 1.8, 0)], closed=True, fc=GND, ec=INK, lw=0.8, + alpha=0.13, zorder=2)) + ax.text(*P(1.92, -1.8, 0), s=" surface", ha="left", va="center", color=INK, + fontsize=9) + # the horizontal cut at z = 10 m + ax.add_patch(Polygon([P(-1.7, -1.6, zc), P(1.7, -1.6, zc), P(1.7, 1.6, zc), + P(-1.7, 1.6, zc)], closed=True, fc=FLD, ec=FLD, lw=1.1, + alpha=0.20, zorder=3)) + ax.text(*P(1.72, -1.6, zc), s=" the $(x,y)$-plane at $z=10$ m", ha="left", + va="center", color=FLD, fontsize=9) + ax.text(*P(-1.78, 0, 0.62), s="the $(x,z)$-plane\nat $y=0$ ", ha="right", + va="center", color=FLD, fontsize=9) + + # the loop, 1 -> 2 -> 3 -> 4: clockwise seen from above, with z downward + verts = [(-L, -L), (L, -L), (L, L), (-L, L)] + for k in range(4): + x0, y0 = verts[k] + x1, y1 = verts[(k + 1) % 4] + ax.plot(*zip(P(x0, y0, 0), P(x1, y1, 0)), color=SRC, lw=2.6, zorder=6, + solid_capstyle="round") + arrow(ax, P(x0 + 0.40 * (x1 - x0), y0 + 0.40 * (y1 - y0), 0), + P(x0 + 0.60 * (x1 - x0), y0 + 0.60 * (y1 - y0), 0), scale=13, z=7) + for (vx, vy), k in zip(verts, "1234"): + px, py = P(vx, vy, 0) + ax.text(px + (0.10 if vx > 0 else -0.10), py + 0.06, k, ha="center", + va="bottom", color=SRC, fontsize=10.5, zorder=8) + ax.text(-2.40, 0.88, "square loop on the surface\n$L_x = L_y = 100$ m\n" + "$I$ switched on at $t=0$", ha="left", va="top", color=SRC, + fontsize=9.5, zorder=8, linespacing=1.45) + + # axes, from the centre of the loop + for (dx, dy, dz), lab, off in (((0.70, 0, 0), "$x$", (0.10, 0.02)), + ((0, 0.70, 0), "$y$", (-0.10, -0.05)), + ((0, 0, 0.95), "$z$", (0.10, 0.0))): + arrow(ax, P(0, 0, 0), P(dx, dy, dz), color=INK, lw=1.3, scale=12, z=9) + px, py = P(dx, dy, dz) + ax.text(px + off[0], py + off[1], lab, color=INK, fontsize=11, zorder=9, + ha="center", va="center") + + bare(ax, (-2.45, 3.15), (-1.45, 0.95)) + caption(fig, "The field is cut in the vertical plane $y = 0$ and in a horizontal" + " plane at depth $z$, with $D = \\sqrt{4t/\\sigma\\mu}$.") + fig.tight_layout(rect=(0, 0.08, 1, 1)) + fig.savefig("setup_loop.svg", transparent=True, metadata={"Date": None}) + plt.close(fig) + + +if __name__ == "__main__": + sheet(); wire(); ladder(); loop() + print("wrote setup_sheet.svg, setup_wire.svg, setup_ladder.svg, setup_loop.svg") diff --git a/book/3_diffusion_fields/labs/figures/setup_ladder.svg b/book/3_diffusion_fields/labs/figures/setup_ladder.svg new file mode 100644 index 0000000..bd735ad --- /dev/null +++ b/book/3_diffusion_fields/labs/figures/setup_ladder.svg @@ -0,0 +1,1476 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/3_diffusion_fields/labs/figures/setup_loop.svg b/book/3_diffusion_fields/labs/figures/setup_loop.svg new file mode 100644 index 0000000..fda768e --- /dev/null +++ b/book/3_diffusion_fields/labs/figures/setup_loop.svg @@ -0,0 +1,1263 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/3_diffusion_fields/labs/figures/setup_sheet.svg b/book/3_diffusion_fields/labs/figures/setup_sheet.svg new file mode 100644 index 0000000..f776855 --- /dev/null +++ b/book/3_diffusion_fields/labs/figures/setup_sheet.svg @@ -0,0 +1,1242 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/3_diffusion_fields/labs/figures/setup_wire.svg b/book/3_diffusion_fields/labs/figures/setup_wire.svg new file mode 100644 index 0000000..c0f7f45 --- /dev/null +++ b/book/3_diffusion_fields/labs/figures/setup_wire.svg @@ -0,0 +1,1146 @@ + + + + + + + + image/svg+xml + + + Matplotlib v3.11.1, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/book/3_diffusion_fields/labs/fwtools.py b/book/3_diffusion_fields/labs/fwtools.py new file mode 100644 index 0000000..4f44274 --- /dev/null +++ b/book/3_diffusion_fields/labs/fwtools.py @@ -0,0 +1,378 @@ +"""Plotting and self-check helpers for the ECTB2140 *Fields and Waves* labs, +diffusive-fields edition. + +You are **not** expected to read or edit this file during a lab session. It +exists so that your time goes on the physics -- series coefficients, decay +rates, Gaussian kernels -- rather than on plotting boilerplate. + +The self-check functions have the same names and behaviour as in the Lab 1 +and Lab 2 module. The one-dimensional helpers take fields of shape (nt, nx), +one row per time. ``show_map`` and ``show_isosurface`` take two- and +three-dimensional fields, indexed as ``np.meshgrid(..., indexing='ij')`` +builds them, so ``F[ix, iy]`` sits at ``(x[ix], y[iy])``. + +Requires: numpy, matplotlib, plotly. +""" + +from __future__ import annotations + +import numpy as np +import matplotlib.pyplot as plt +from matplotlib.colors import TwoSlopeNorm +import plotly.graph_objects as go + +__all__ = [ + "show_profiles", "show_spacetime", "show_spacetime_slider", "show_records", + "show_map", "show_isosurface", + "check", "check_close", "check_abs", "check_scalar", +] + +# -------------------------------------------------------------------------- +# Figures +# -------------------------------------------------------------------------- + +def _fmt(v, fmt): + return fmt.format(v) if isinstance(fmt, str) else fmt(v) + + +def show_profiles(x, frames, values, *, value_name="t", value_fmt="{:.3g}", + unit="", reference=None, reference_name="initial condition", + xlabel="x [m]", ylabel="", title="", ylim=None, height=430, + ms_per_frame=90, colors=("#00A6D6", "#EC6842", "#7B61FF"), + log_x=False, log_y=False): + """Profiles over time, with a play button and a draggable progress bar. + + ``frames`` is either one array of shape (len(values), nx), or a dict + ``{name: array}`` to draw several curves that evolve together. Press play + to run from the start, or drag the bar to any instant. Both run in the + browser; nothing here needs the kernel once the figure exists. + """ + if not isinstance(frames, dict): + frames = {"profile": frames} + frames = {k: np.asarray(v, float) for k, v in frames.items()} + x = np.asarray(x, float) + allv = np.concatenate([v.ravel() for v in frames.values()]) + lo, hi = (np.nanmin(allv), np.nanmax(allv)) if ylim is None else ylim + pad = 0.06 * (hi - lo if hi > lo else 1.0) + + fig = go.Figure() + if reference is not None: + fig.add_trace(go.Scatter(x=x, y=reference, mode="lines", name=reference_name, + line=dict(color="#8a9199", dash="dash", width=1.5))) + live = [] + for k, (name, arr) in enumerate(frames.items()): + fig.add_trace(go.Scatter(x=x, y=arr[0], mode="lines", name=name, + line=dict(color=colors[k % len(colors)], + width=2.5 if k == 0 else 2.0))) + live.append(len(fig.data) - 1) + + n_steps = len(values) + fig.frames = [go.Frame(name=str(k), + data=[go.Scatter(y=arr[k]) for arr in frames.values()], + traces=live) + for k in range(n_steps)] + still = dict(mode="immediate", frame=dict(duration=0, redraw=False), + transition=dict(duration=0)) + steps = [dict(method="animate", label=_fmt(v, value_fmt), args=[[str(k)], still]) + for k, v in enumerate(values)] + + fig.update_layout( + title=title, height=height, margin=dict(l=60, r=20, t=50, b=30), + xaxis=dict(title=xlabel, type="log" if log_x else "linear"), + yaxis=dict(title=ylabel, type="log" if log_y else "linear", + range=([np.log10(max(lo, 1e-300)), np.log10(max(hi, 1e-299))] + if log_y else [lo - pad, hi + pad])), + legend=dict(x=0.99, xanchor="right", y=0.99), + sliders=[dict(active=0, steps=steps, len=0.82, x=0.18, y=0, pad=dict(t=50, b=8), + currentvalue=dict(prefix=f"{value_name} = ", suffix=unit, + font=dict(size=13)))], + updatemenus=[dict(type="buttons", direction="left", showactive=False, + x=0.0, y=0, xanchor="left", yanchor="top", pad=dict(t=55, b=8), + buttons=[ + dict(label="▶ play", method="animate", + args=[None, dict(mode="immediate", fromcurrent=False, + frame=dict(duration=ms_per_frame, redraw=False), + transition=dict(duration=0))]), + dict(label="❚❚", method="animate", args=[[None], still])])]) + fig.show() + + +def show_spacetime(x, t, T, *, t_label="t [s]", x_label="x [m]", c_label="T [K]", + title="", signed=None, log_t=True, marks=None, curve=None, + curve_label="prediction", deeper_down=False): + """Colour map of T(x, t): time along the horizontal axis, position vertical. + + A signed field gets a diverging colour map centred on zero; a positive one + gets a sequential map. ``marks`` is an optional list of (t, x) points to + overlay, e.g. predicted peak times. + """ + T = np.asarray(T, float) + if signed is None: + signed = np.nanmin(T) < 0 < np.nanmax(T) + fig, ax = plt.subplots(figsize=(8.2, 3.6)) + if signed: + vmax = np.nanmax(np.abs(T)) + im = ax.pcolormesh(t, x, T.T, cmap="RdBu_r", shading="auto", + norm=TwoSlopeNorm(0.0, -vmax, vmax)) + else: + im = ax.pcolormesh(t, x, T.T, cmap="inferno", shading="auto", vmin=0) + if curve is not None: + ax.plot(curve[0], curve[1], "--", color="#00A6D6", lw=2, label=curve_label) + ax.legend(loc="upper left", fontsize=8) + if marks is not None: + mt, mx = zip(*marks) + ax.plot(mt, mx, "o", mfc="none", mec="#00A6D6", mew=1.5, ms=7, label="predicted peak") + ax.legend(loc="upper left", fontsize=8) + if log_t: + ax.set_xscale("log") + ax.set_xlim(np.min(t), np.max(t)) # an overlaid curve must not stretch the axis + if deeper_down: # depth axes read downward + ax.invert_yaxis() + ax.set_xlabel(t_label); ax.set_ylabel(x_label); ax.set_title(title) + fig.colorbar(im, ax=ax, label=c_label, pad=0.02) + fig.tight_layout() + plt.show() + + +def show_spacetime_slider(x, t, maps, values, *, value_name="a", value_fmt="{:.3g}", + unit="", t_label="t [s]", x_label="x [m]", c_label="T [K]", + title="", marks=None, height=430): + """One space-time map per slider position, for a parameter of the problem. + + ``maps`` has shape (len(values), len(t), len(x)). ``marks[k]`` optionally + draws a vertical line at that time on map k, e.g. a predicted merge time. + The slider updates the map and the line together, client-side. + """ + maps = np.asarray(maps, float) + x, t = np.asarray(x, float), np.asarray(t, float) + zmin, zmax = float(np.nanmin(maps)), float(np.nanmax(maps)) + + def line(k): + if marks is None or not np.isfinite(marks[k]) or marks[k] <= t[0]: + return [] + return [dict(type="line", x0=marks[k], x1=marks[k], y0=x[0], y1=x[-1], + xref="x", yref="y", line=dict(color="#00A6D6", width=2, dash="dash"))] + + fig = go.Figure(go.Heatmap(z=maps[0].T, x=t, y=x, colorscale="Inferno", + zmin=zmin, zmax=zmax, colorbar=dict(title=c_label))) + steps = [dict(method="update", label=_fmt(v, value_fmt), + args=[{"z": [m.T]}, {"shapes": line(k)}]) + for k, (v, m) in enumerate(zip(values, maps))] + fig.update_layout( + title=title, height=height, margin=dict(l=60, r=20, t=50, b=30), + xaxis=dict(title=t_label, type="log"), yaxis_title=x_label, + shapes=line(0), + sliders=[dict(active=0, steps=steps, len=0.82, x=0.12, y=0, pad=dict(t=50, b=8), + currentvalue=dict(prefix=f"{value_name} = ", suffix=unit, + font=dict(size=13)))]) + fig.show() + + +def show_records(t, records, *, t_label="t [s]", y_label="T [K]", title="", + peaks=None, log_t=True): + """Time series at fixed positions, as a thermometer or a receiver records them. + + ``records`` maps a label to an array over ``t``. ``peaks`` optionally maps + the same labels to a predicted (t_peak, value_peak), drawn as an open circle. + """ + fig, ax = plt.subplots(figsize=(8.2, 3.4)) + _ls = ("-", "--", "-.", ":") # not colour alone: the C2/C3 pair is a common confusion + for k, (lab, y) in enumerate(records.items()): + ax.plot(t, y, color=f"C{k}", ls=_ls[k % 4], lw=2, label=lab) + if peaks and lab in peaks: + ax.plot(*peaks[lab], "o", mfc="none", mec=f"C{k}", mew=1.5, ms=9) + if log_t: + ax.set_xscale("log") + ax.set_xlabel(t_label); ax.set_ylabel(y_label); ax.set_title(title) + ax.grid(alpha=0.3); ax.legend(fontsize=8) + fig.tight_layout() + plt.show() + + +def _arrow_lines(X, Y, U, V, length): + """Unit arrows at (X, Y), as one broken line trace. NaN separates them.""" + n = np.hypot(U, V) + n = np.where(n > 0, n, 1.0) + u, v = U / n * length, V / n * length + x0, y0 = X - 0.5 * u, Y - 0.5 * v + x1, y1 = X + 0.5 * u, Y + 0.5 * v + ang = np.arctan2(v, u) + b = 0.34 * length + lx, ly = x1 - b * np.cos(ang - 0.42), y1 - b * np.sin(ang - 0.42) + rx, ry = x1 - b * np.cos(ang + 0.42), y1 - b * np.sin(ang + 0.42) + nan = np.full_like(x0, np.nan) + xs = np.stack([x0, x1, nan, lx, x1, rx, nan], axis=-1).ravel() + ys = np.stack([y0, y1, nan, ly, y1, ry, nan], axis=-1).ravel() + return xs, ys + + +def show_map(x, y, frames, values, *, value_name="t", value_fmt="{:.3g}", unit="", + x_label="x [m]", y_label="y [m]", c_label="", title="", signed=None, + arrows=None, arrow_every=8, zmin=None, zmax=None, per_frame_scale=False, + log_c=False, log_floor=1e-4, y_down=False, equal_aspect=True, + height=560, ms_per_frame=140): + """A field over a plane, with a play button and a draggable slider. + + ``frames`` has shape (len(values), len(x), len(y)): one map per slider + position, indexed the way ``np.meshgrid(..., indexing='ij')`` builds it. + ``arrows`` is an optional pair ``(U, V)`` of the same shape, drawn as unit + arrows every ``arrow_every`` points to show direction only. + ``per_frame_scale=True`` rescales the colour axis on every frame, which + shows the shape of a field whose amplitude changes by decades. + ``log_c=True`` colours by the base-10 logarithm instead, keeping the shape + of the pattern readable where the amplitude spans several decades; values + below ``log_floor`` times the largest are clipped. + """ + x, y = np.asarray(x, float), np.asarray(y, float) + frames = np.asarray(frames, float) + if log_c: + if signed: + raise ValueError("log_c colours a magnitude, so the field must not change sign") + signed = False + scale = np.nanmax(np.abs(frames), axis=(1, 2), keepdims=True) if per_frame_scale \ + else np.nanmax(np.abs(frames)) + frames = np.log10(np.maximum(np.abs(frames) / scale, log_floor)) + per_frame_scale = False + zmin, zmax = np.log10(log_floor), 0.0 + if signed is None: + signed = np.nanmin(frames) < 0 < np.nanmax(frames) + if per_frame_scale: + lim = [float(np.nanmax(np.abs(f))) or 1.0 for f in frames] + rng = [(-L, L) if signed else (0.0, L) for L in lim] + else: + hi = float(np.nanmax(np.abs(frames))) if signed else float(np.nanmax(frames)) + lo = -hi if signed else float(min(0.0, np.nanmin(frames))) + rng = [(lo if zmin is None else zmin, hi if zmax is None else zmax)] * len(values) + if log_c: + rng = [(zmin, zmax)] * len(values) + cs = "RdBu_r" if signed else "Inferno" + + def heat(k): + return go.Heatmap(z=frames[k].T, x=x, y=y, colorscale=cs, + zmin=rng[k][0], zmax=rng[k][1], zsmooth="best", + colorbar=dict(title=c_label)) + + quiver = None + if arrows is not None: + U, V = (np.asarray(a, float) for a in arrows) + sx, sy = x[::arrow_every], y[::arrow_every] + Xa, Ya = np.meshgrid(sx, sy, indexing="ij") + step = float(min(sx[1] - sx[0], sy[1] - sy[0])) * 0.85 + quiver = [_arrow_lines(Xa, Ya, U[k][::arrow_every, ::arrow_every], + V[k][::arrow_every, ::arrow_every], step) + for k in range(len(values))] + + fig = go.Figure(heat(0)) + if quiver is not None: + # cyan, not white: Inferno runs to near-white at the top, so white arrows + # vanish over the bright core exactly where the pattern is worth reading + fig.add_trace(go.Scatter(x=quiver[0][0], y=quiver[0][1], mode="lines", + line=dict(color="#00A6D6", width=1.4), + hoverinfo="skip", showlegend=False)) + data_k = (lambda k: [heat(k), go.Scatter(x=quiver[k][0], y=quiver[k][1])]) if quiver \ + else (lambda k: [heat(k)]) + fig.frames = [go.Frame(name=str(k), data=data_k(k), + traces=list(range(len(fig.data)))) for k in range(len(values))] + + still = dict(mode="immediate", frame=dict(duration=0, redraw=True), + transition=dict(duration=0)) + steps = [dict(method="animate", label=_fmt(v, value_fmt), args=[[str(k)], still]) + for k, v in enumerate(values)] + fig.update_layout( + title=title, height=height, margin=dict(l=60, r=20, t=50, b=30), + xaxis=dict(title=x_label, constrain="domain"), + yaxis=dict(title=y_label, autorange="reversed" if y_down else True, + scaleanchor="x" if equal_aspect else None, scaleratio=1), + sliders=[dict(active=0, steps=steps, len=0.80, x=0.18, y=0, pad=dict(t=50, b=8), + currentvalue=dict(prefix=f"{value_name} = ", suffix=unit, + font=dict(size=13)))], + updatemenus=[dict(type="buttons", direction="left", showactive=False, + x=0.0, y=0, xanchor="left", yanchor="top", pad=dict(t=55, b=8), + buttons=[ + dict(label="\u25b6 play", method="animate", + args=[None, dict(mode="immediate", fromcurrent=False, + frame=dict(duration=ms_per_frame, redraw=True), + transition=dict(duration=0))]), + dict(label="\u275a\u275a", method="animate", + args=[[None], still])])]) + fig.show() + + +def show_isosurface(x, y, z, V, *, levels=(0.1, 0.3, 0.6), opacity=0.3, c_label="", + title="", wire=None, wire_name="source", x_label="x [m]", + y_label="y [m]", z_label="z [m]", z_down=True, height=600): + """Nested translucent surfaces of constant ``V``, free to rotate and zoom. + + ``V`` has shape (len(x), len(y), len(z)), built with ``indexing='ij'``. + ``levels`` are fractions of the largest value in ``V``. Transparency keeps + the inner surfaces visible through the outer ones. ``wire`` is an optional + (xs, ys, zs) polyline, e.g. the loop that generated the field. + """ + x, y, z = (np.asarray(a, float) for a in (x, y, z)) + V = np.asarray(V, float) + X, Y, Z = np.meshgrid(x, y, z, indexing="ij") + vmax = float(np.nanmax(V)) + lo, hi = sorted(float(f) * vmax for f in (min(levels), max(levels))) + + fig = go.Figure(go.Isosurface( + x=X.ravel(), y=Y.ravel(), z=Z.ravel(), value=V.ravel(), + isomin=lo, isomax=hi, surface_count=len(levels), opacity=opacity, + colorscale="Inferno", caps=dict(x_show=False, y_show=False, z_show=False), + colorbar=dict(title=c_label))) + if wire is not None: + fig.add_trace(go.Scatter3d(x=wire[0], y=wire[1], z=wire[2], mode="lines", + line=dict(color="#00A6D6", width=6), name=wire_name)) + fig.update_layout( + title=title, height=height, margin=dict(l=0, r=0, t=50, b=0), + scene=dict(xaxis_title=x_label, yaxis_title=y_label, zaxis_title=z_label, + zaxis=dict(autorange="reversed" if z_down else True), + aspectmode="data")) + fig.show() + + +# -------------------------------------------------------------------------- +# Self-checks (same behaviour as the Lab 1 and Lab 2 module) +# -------------------------------------------------------------------------- + +def check(label: str, ok: bool, hint: str = "") -> None: + """Report a pass, or raise with a hint about what to look at.""" + if ok: + print(f" [ok] {label}") + else: + raise AssertionError(f"{label} -- {hint}" if hint else label) + + +def check_close(label: str, got, want, rtol=0.05, where=None, hint: str = "") -> None: + """Compare two arrays where both are finite (and where `where` is True).""" + got, want = np.asarray(got, float), np.broadcast_to(np.asarray(want, float), np.shape(got)) + m = np.isfinite(got) & np.isfinite(want) + if where is not None: + m = m & where + if not m.any(): + raise AssertionError(f"{label} -- nothing left to compare; the mask removed every point") + rel = np.abs(got[m] - want[m]) / np.maximum(np.abs(want[m]), 1e-30) + worst = float(np.max(rel)) + check(f"{label}: worst error {worst:.2%}", worst < rtol, + hint or f"worst relative error {worst:.2%} exceeds {rtol:.0%}") + + +def check_abs(label: str, got, atol, where=None, hint: str = "") -> None: + """Compare an array against zero on an absolute scale, in the field's own units.""" + got = np.asarray(got, float) + m = np.isfinite(got) + if where is not None: + m = m & where + if not m.any(): + raise AssertionError(f"{label} -- nothing left to compare") + worst = float(np.max(np.abs(got[m]))) + check(f"{label}: worst |value| {worst:.2e}", worst < atol, + hint or f"worst deviation {worst:.2e} exceeds {atol:.1e}") + + +def check_scalar(label: str, got: float, want: float, rtol: float = 0.01, + unit: str = "", hint: str = "") -> None: + """Compare two single numbers and report the relative discrepancy.""" + got, want = float(got), float(want) + rel = abs(got - want) / max(abs(want), 1e-30) + check(f"{label}: {got:.4g}{unit} vs {want:.4g}{unit} ({rel:.2%} apart)", + rel < rtol, hint or f"these should agree to better than {rtol:.0%}") diff --git a/book/3_diffusion_fields/labs/week05_diffusion.md b/book/3_diffusion_fields/labs/week05_diffusion.md new file mode 100644 index 0000000..7506c98 --- /dev/null +++ b/book/3_diffusion_fields/labs/week05_diffusion.md @@ -0,0 +1,640 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +mystnb: + # Workbook page: the task cells contain `___` blanks by design, so it must + # not be executed at build time. Readers run it themselves with Live Code. + execution_mode: 'off' +--- + +# Lab 5: Diffusive Fields + +:::{admonition} Computer lab +:class: note + +A practical companion to the lecture on [the heat equation in one dimension](../heat_equation_1d.md). Each task states a physical question, gives the steps, and ends with a self-check you can run. + +Everything you write here is plain NumPy. The module `fwtools` only draws and checks: `fw.show_profiles` (a profile per instant, with a play button), `fw.show_spacetime` (a colour map over position and time), `fw.show_records` (time series at fixed positions) and the `fw.check...` functions. Every slider runs in the browser. +::: + +## Learning objectives + +- **Decaying modes.** Build an initial temperature from a Fourier series and explain why mode $n$ decays at $\kappa(n\pi/L)^2$, so fine structure goes first. +- **Boundaries.** Ends held at a fixed temperature let heat leave; insulated ends conserve it and drive the bar to its mean. +- **Superposition.** Evolve any initial temperature with the Green's function, and turn the $t\propto x^2$ it implies into a measurement of $\kappa$ in a bar. The same kernel measures depth in the Earth in [Lab 6](./week06_em_diffusion.md). + +--- + +## Part 0 — Setup + +Run this once. It contains no physics: it fetches two packages the browser lacks and locates `fwtools`. + +```{code-cell} ipython3 +import sys, pathlib + +import numpy as np +import matplotlib.pyplot as plt + +# --- Live Code housekeeping, not part of the physics ----------------------- +try: + import plotly.io as pio +except ModuleNotFoundError: + print("Fetching plotly. A few seconds, and only the first time...") + import micropip + await micropip.install("plotly") + import plotly.io as pio + +try: + import nbformat # noqa: F401 +except ModuleNotFoundError: + import micropip, types + try: + await micropip.install("nbformat") + except Exception: + _nb = types.ModuleType("nbformat") + _nb.__version__ = "5.10.4" + sys.modules["nbformat"] = _nb + +for _p in (".", "book/3_diffusion_fields/labs"): + if (pathlib.Path(_p) / "fwtools.py").exists(): + sys.path.insert(0, _p) + break +try: + import fwtools as fw +except ModuleNotFoundError: + from pyodide.http import pyfetch + _r = await pyfetch("fwtools.py") + pathlib.Path("fwtools.py").write_bytes(await _r.bytes()) + import fwtools as fw + +pio.renderers.default = "plotly_mimetype+notebook" +# --------------------------------------------------------------------------- +print("ready") +``` + +--- + +## Part 1 — A bar of finite length + +A copper bar of length $L = 0.5$ m has thermal diffusivity $\kappa = 1.1\times10^{-4}$ m²/s. Its temperature $T$ is measured from a reference value, so it can be negative. Without sources, the temperature obeys + +$$ \partial_t T = \kappa\,\partial_x^2 T . $$ + +The only time scale the bar has is $L^2/\kappa \approx 38$ min, so the natural clock is the Fourier number $\mathrm{Fo} = \kappa t/L^2$. The two ways of closing the ends lead to different series and to a different final state. + +```{figure} figures/bar_boundary_conditions.svg +:name: fig-lab5-bcs +:width: 80% + +The two bars of this part. In Tasks 1 and 2 the ends are clamped to reservoirs at the reference temperature. In Task 3 they are insulated. +``` + +### Task 1 — build the initial temperature from sines + +With both ends held at $T=0$, separation of variables gives + +$$ T(x,t) = \sum_{n=1}^{\infty} C_n \sin\!\left(\frac{n\pi x}{L}\right) \exp\!\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right], \qquad C_n = \frac{2}{L}\int_0^L h(x)\sin\!\left(\frac{n\pi x}{L}\right)\mathrm{d}x , $$ + +where the coefficient formula follows from the orthogonality of the sines. At $t=0$ the series must rebuild the initial temperature $h(x)$. Here $h$ is $0$, $-1$, $1$, $0$ K on the four quarters of the bar. + +1. Compute all $C_n$ at once by projecting $h$ onto every row of `S`. +2. Write the partial sum of the first `m` modes. +3. Drag the slider. **Before you do**, predict which coefficients vanish, using the symmetry of $h$ about $x=L/2$. + +```{code-cell} ipython3 +L, kappa = 0.5, 1.1e-4 # copper bar: length [m], thermal diffusivity [m^2/s] +ncell, N = 1200, 400 # grid cells, number of modes kept +dx = L / ncell +x = (np.arange(ncell) + 0.5) * dx # cell centres, so an integral is a plain sum times dx +n = np.arange(1, N + 1) +S = np.sin(np.outer(n, np.pi * x / L)) # row n-1 is sin(n pi x / L), shape (N, ncell) +h = np.where(x < L/4, 0.0, np.where(x < L/2, -1.0, + np.where(x < 3*L/4, 1.0, 0.0))) # initial temperature [K] +print(f"L^2/kappa = {L**2/kappa:.0f} s; slowest possible mode, tau_1 = L^2/(kappa pi^2)" + f" = {L**2/(kappa*np.pi**2):.0f} s") + +# Task 1 -- two blanks. An integral over the bar is np.sum(...) * dx; summing along +# axis=1 of an (N, ncell) array does all N integrals at once. +C = ___ # all C_n, shape (N,) +partial = lambda m: ___ # sum of the first m modes at t = 0, shape (ncell,) + +# --- given: the partial sums, one per slider position --- +Ns = np.array([1, 2, 4, 6, 10, 20, 40, 100, 400]) +fw.show_profiles(x, np.array([partial(m) for m in Ns]), Ns, value_name="modes kept", + value_fmt="{:d}", reference=h, reference_name="h(x)", + ylabel="T [K]", title="Partial sums of the sine series") +print("C_1 .. C_6 =", np.round(C[:6], 4)) + +# --- self-check (leave this alone) --- +_C_exact = 2 * (2*np.cos(n*np.pi/2) - np.cos(n*np.pi/4) - np.cos(3*n*np.pi/4)) / (np.pi * n) +fw.check_abs("the first 40 C_n match the closed form", C[:40] - _C_exact[:40], 1e-3, + hint="C_n = (2/L) * integral of h(x) sin(n pi x/L) dx, for every n at once") +_away = np.min(np.abs(x[:, None] - np.array([L/4, L/2, 3*L/4])), axis=1) > 0.04 +fw.check_abs("400 modes rebuild h(x) more than 4 cm from a jump", partial(N) - h, 0.02, where=_away, + hint="partial(m) should weight the first m rows of S by the first m coefficients") +``` + +:::{admonition} Solution — Task 1 +:class: dropdown + +```python +C = (2 / L) * np.sum(h * S, axis=1) * dx +partial = lambda m: C[:m] @ S[:m] +``` +::: + +:::{admonition} Only even modes appear, and the overshoot at a jump never shrinks +:class: important dropdown + +$h$ is antisymmetric about $x=L/2$, while $\sin(n\pi x/L)$ is symmetric about that point for odd $n$ and antisymmetric for even $n$. The projection of an antisymmetric function onto a symmetric one is zero, so $C_1=C_3=C_5=\dots=0$. + +Near each jump the partial sums overshoot by about 9% of the jump. At $x=L/2$ the jump is 2 K, so the peak reaches about 1.18 K, whether you keep 10 modes or 100. Adding terms squeezes the overshoot towards the jump without lowering it; at 400 modes it becomes narrower than the grid spacing, and the plotted peak reads slightly lower. This is the Gibbs phenomenon: the series converges at every point, but not uniformly near a discontinuity. +::: + +### Task 2 — let it diffuse + +Every mode keeps its shape and decays with its own time constant + +$$ \tau_n = \frac{L^2}{\kappa\,n^2\pi^2} . $$ + +Mode $n$ dies $n^2$ times faster than mode 1. **Predict** which mode is the last one visible, given the coefficients of Task 1. + +1. Build the decay factors for all times and all modes in one array. +2. Weight each mode by $C_n$ and by its decay, and sum the modes. + +```{code-cell} ipython3 +t = np.logspace(-1, np.log10(0.25 * L**2 / kappa), 90) # 0.1 s .. 568 s, i.e. Fo = 0.25 + +# Task 2 -- two blanks. +D = ___ # exp(-kappa (n pi/L)^2 t), shape (len(t), N) +T = ___ # T(x, t), shape (len(t), nx) + +# --- given: the space-time map, then the profiles as a movie --- +fw.show_spacetime(x, t, T, t_label="t [s]", x_label="x [m]", c_label="T [K]", + title="Ends held at T = 0") +fw.show_profiles(x, T[::2], t[::2], value_name="t", value_fmt="{:.3g}", unit=" s", + reference=h, ylabel="T [K]", title="Ends held at T = 0", ylim=(-1.2, 1.2)) + +# --- self-check (leave this alone) --- +fw.check("T has one row per time and one column per grid cell", np.shape(T) == (len(t), ncell)) +_i1, _i2 = np.argmin(np.abs(t - 0.05*L**2/kappa)), np.argmin(np.abs(t - 0.10*L**2/kappa)) +_A = np.max(np.abs(T), axis=1) +_rate = np.log(_A[_i1] / _A[_i2]) / (t[_i2] - t[_i1]) +fw.check_scalar("late-time decay rate of your T equals kappa (2 pi/L)^2", _rate, + kappa * (2*np.pi/L)**2, rtol=0.01, unit=" 1/s", + hint="each mode needs its own exponent kappa (n pi/L)^2 t") +``` + +:::{admonition} Solution — Task 2 +:class: dropdown + +```python +D = np.exp(-kappa * (n * np.pi / L)**2 * t[:, None]) +T = (C * D) @ S +``` +::: + +:::{admonition} Mode 2 survives, because mode 1 was never there +:class: important dropdown + +The sharp corners of $h$ are made of high modes, and those vanish within seconds: after one second, modes above $n\approx 15$ have decayed by a factor of $e$. By $t\approx 60$ s only $n=2$ and a trace of $n=4$ remain, so the profile has become a single sine wave that shrinks without changing shape. Mode 1 would have decayed four times more slowly still, but $h$ contains none of it. The heat flows out through the clamped ends and between the warm and cold halves, and the bar returns to the reference temperature. + +The measured decay rate is the second eigenvalue, $\kappa(2\pi/L)^2 = 0.0174$ s$^{-1}$. A long-time temperature record thus reveals the lowest mode present, and with it $\kappa/L^2$. +::: + +### Task 3 — insulate the ends + +With $\partial_xT = 0$ at both ends, no heat crosses them. The eigenfunctions become cosines, and $\lambda=0$ is now an eigenvalue: + +$$ T(x,t) = C_0 + \sum_{n=1}^{\infty} C_n \cos\!\left(\frac{n\pi x}{L}\right)\exp\!\left[-\kappa\left(\frac{n\pi}{L}\right)^2 t\right], \qquad C_0 = \frac{1}{L}\int_0^L h\,\mathrm{d}x, \quad C_n = \frac{2}{L}\int_0^L h\cos\!\left(\frac{n\pi x}{L}\right)\mathrm{d}x . $$ + +The initial temperature is now $1$, $-1$, $1$ K on the three thirds of the bar. The cosine projection is given; write $C_0$, the one mode the clamped bar of Task 2 did not have. **Predict** the temperature at late times, and whether the heat content $\int_0^L T\,\mathrm{d}x$ changes. + +```{code-cell} ipython3 +Cc = np.cos(np.outer(n, np.pi * x / L)) # row n-1 is cos(n pi x / L) +h_ins = np.where(x < L/3, 1.0, np.where(x < 2*L/3, -1.0, 1.0)) # initial temperature [K] + +# Task 3 -- one blank: the n = 0 coefficient, the mode the clamped bar did not have. +C0 = ___ # the n = 0 coefficient [K] + +# --- given: the rest is Task 2 with cosines in place of sines --- +Cn = (2 / L) * np.sum(h_ins * Cc, axis=1) * dx # C_n for n = 1..N, shape (N,) +T_ins = C0 + (Cn * D) @ Cc # T(x, t), reusing D from Task 2 + +Q = np.sum(T_ins, axis=1) * dx # heat content, per unit area and heat capacity [K m] + +# --- given: the same two views as Task 2, to be compared with it --- +fw.show_spacetime(x, t, T_ins, t_label="t [s]", x_label="x [m]", c_label="T [K]", + title="Insulated ends") +fw.show_profiles(x, T_ins[::2], t[::2], value_name="t", value_fmt="{:.3g}", unit=" s", + reference=h_ins, ylabel="T [K]", title="Insulated ends", ylim=(-1.2, 1.2)) +print(f"heat content: min {Q.min():.6f}, max {Q.max():.6f} K m over {t[0]:.1f} s .. {t[-1]:.0f} s") + +# --- self-check (leave this alone) --- +fw.check_close("heat content stays at C0 L = 1/6 K m at every time", Q, (1/3) * L, rtol=1e-3) +_away3 = np.min(np.abs(x[:, None] - np.array([L/3, 2*L/3])), axis=1) > 0.02 +fw.check_abs("at t = 0.1 s the series still equals h(x) away from the jumps", + T_ins[0] - h_ins, 0.01, where=_away3, + hint="compare your cosine projection with the sine projection of Task 1") +``` + +:::{admonition} Solution — Task 3 +:class: dropdown + +```python +C0 = np.sum(h_ins) * dx / L +``` +::: + +:::{admonition} Insulated ends conserve the heat, and the bar settles at its mean +:class: important dropdown + +Every cosine with $n\ge1$ integrates to zero over the bar, so the heat content is $C_0L$ at all times, fixed by $h$ alone. The mode $n=0$ has decay rate zero, so it is all that remains: $T\to C_0 = 1/3$ K everywhere. In Task 2 every eigenvalue was positive and the temperature went to zero, because the clamped ends could absorb or supply heat. The boundary condition, not the equation, decides where the heat ends up. +::: + +--- + +## Part 2 — An infinitely long wire + +On an infinite wire the lecture notes solve the same equation twice. First in closed form, for an initial Gaussian $T(x,0) = T_0\exp(-x^2/L^2)$: + +$$ T(x,t) = \frac{T_0 L}{\sqrt{4\kappa t + L^2}}\exp\!\left(-\frac{x^2}{4\kappa t + L^2}\right). $$ + +Then again as a cosine series, by putting the wire in a box of length $2M$ and letting $M$ grow. Task 7 takes up that second route; Parts 2 and 3 use the closed form, because it is the one you can read. + +In this part and again in Task 7, $L$ is the width of the initial Gaussian and not a length of wire; the lecture notes use the one letter for both. The code keeps them apart: `L` is the bar of Part 1, `Lg` the Gaussian here, `Lw` the Gaussian of Task 7. Time enters only through $\kappa t$, which has units of m², so every result below holds for any material. The figures below use $L=3$ m, $-10 kt[0]}, + t_label=r"$\kappa t$ [m$^2$]", y_label="T [K]", + title="Thermometer records; circles mark the predicted peaks") + +# --- self-check (leave this alone) --- +_xw = np.linspace(-2000.0, 2000.0, 200001) +_heat = [np.sum(T_gauss(_xw, k)) * (_xw[1] - _xw[0]) for k in (0.1, 10.0, 1000.0)] +fw.check_close("heat content T0 L sqrt(pi) at kappa t = 0.1, 10, 1000 m^2", + _heat, T0 * Lg * np.sqrt(np.pi), rtol=1e-3, + hint="the prefactor must shrink exactly as fast as the width grows") +_ktf = np.logspace(-1, 3, 4001) +_rec = T_gauss(5.0, _ktf) +fw.check_scalar("your kt_peak(5 m) against the peak of your own record", kt_peak(5.0), + _ktf[np.argmax(_rec)], rtol=0.01, unit=" m^2") +fw.check_scalar("peak temperature at 5 m", np.max(_rec), T0 * Lg / (np.sqrt(2*np.e) * 5.0), + rtol=0.01, unit=" K") +``` + +:::{admonition} Solution — Task 4 +:class: dropdown + +```python +def T_gauss(x, kt): + return T0 * Lg / np.sqrt(4*kt + Lg**2) * np.exp(-x**2 / (4*kt + Lg**2)) + +def kt_peak(x): + return (2*x**2 - Lg**2) / 4 +``` +::: + +:::{admonition} The heat spreads without loss, and a farther thermometer answers later and weaker +:class: important dropdown + +The width grows as $\sqrt{4\kappa t+L^2}$, and the amplitude falls by exactly the same factor, so the area under the profile stays $T_0L\sqrt\pi$. With no ends, no heat is lost; it is only redistributed. At late times the temperature everywhere falls as $t^{-1/2}$. + +The thermometers show the two faces of diffusion. The peak arrives at $\kappa t_p\propto x^2$: twice as far away takes four times as long. Its height falls as $1/\lvert x\rvert$. Inside $\lvert x\rvert2a^2$ the profile has a single maximum, and it becomes ever harder to distinguish from one Gaussian of twice the heat. Sources that are closer together merge sooner, as $a^2$. For $a thresh)]) +t_dep = np.array(t_dep) + +slope, intercept = np.polyfit(xcs**2, t_dep, 1) +kappa_fit = 1 / (4 * slope * np.log(1 / thresh)) +plt.figure(figsize=(5.2, 3.2)) +plt.plot(xcs**2, t_dep, "o", color="#00A6D6", label="measured") +plt.plot(xcs**2, slope * xcs**2 + intercept, "-", color="#8a9199", + label=f"fit: $\\kappa$ = {kappa_fit:.2e} m$^2$/s") +plt.xlabel("$x_c^2$ [m$^2$]"); plt.ylabel("departure time [s]") +plt.grid(alpha=0.3); plt.legend(fontsize=8); plt.tight_layout(); plt.show() +print(f"departure times [s]: {np.round(t_dep, 2)}") +print(f"intercept: {intercept:.2f} s (-w^2/(4 kappa) = {-w_b**2/(4*kappa):.2f} s)") +print(f"kappa from the fit: {kappa_fit:.3e} m^2/s (the bar was built with {kappa:.3e})") + +# --- self-check (leave this alone) --- +_h_check = np.exp(-(x - 0.15)**2 / w_b**2)[::4] +fw.check_abs("at t = 0.1 s the superposition reproduces the series solution", + T_free(t6[0], _h_check) - bar[0], 1e-6, + hint="the kernel must carry unit heat: check the 1/sqrt(4 pi kappa t) factor " + "and that the sum over x' is multiplied by dxs") +fw.check_scalar("kappa recovered from the departure times", kappa_fit, kappa, rtol=0.05, + unit=" m^2/s") +``` + +:::{admonition} Solution — Task 6 +:class: dropdown + +```python +def T_free(tv, h_on_grid): + G = np.exp(-d2 / (4 * kappa * tv)) / np.sqrt(4 * np.pi * kappa * tv) + return G @ h_on_grid * dxs +``` +::: + +:::{admonition} The ends are felt when the tail reaches them, and that measures $\kappa$ +:class: important dropdown + +The bump spreads to width $\sqrt{4\kappa t + w^2}$, so the temperature at the near end, as a +fraction of the peak, is $\exp[-x_c^2/(4\kappa t + w^2)]$. Setting that ratio to the threshold +$\theta$ gives + +$$ 4\kappa\,t_{\text{dep}} = \frac{x_c^2}{\ln(1/\theta)} - w^2 , $$ + +a straight line in $x_c^2$, which is what the second figure shows. Its slope is +$1/(4\kappa\ln(1/\theta))$, so the fit returns $\kappa$ to about 1%. The intercept is negative: +$-w^2/(4\kappa) = -2.05$ s predicted against $-1.96$ s measured, the head start the bump gets from +the width it already had at $t=0$. + +$\theta$ cancels out of $\kappa$ because the Gaussian tail is exactly log-quadratic, so moving the +threshold scales every departure time by one common factor and the slope absorbs it. Set `thresh` +to 0.002 and to 0.02: the nearest bump departs at 1.7 s instead of 4.0 s, yet $\kappa$ comes back as +$1.08\times10^{-4}$ and $1.09\times10^{-4}$ m²/s against the $1.09\times10^{-4}$ of the 1% run. A bump +whose tail was not Gaussian would not cancel. Push `thresh` to 0.05 and the fit finally drifts 5% +low, because by then the departure is being read off the shoulder of the bump rather than its tail. + +Two things are worth taking from this. A boundary makes itself felt through the tail of the +distribution, long before the diffusion length $\sqrt{4\kappa t}$ equals the distance to it. +And the same $t\propto x^2$ that set the peak time in Task 4 sets this departure time, because +a diffusive field has only one way to convert a distance into a time. +::: + + +### Task 7 — how big a box, and how many modes? + +Part 2 used the closed form on the infinite wire. The lecture notes reach the same field a second +way: put the wire in a box of length $2M$, expand the initial Gaussian in cosines, and let each +mode decay at its own rate. With $M\gg L$ the coefficients can be integrated in closed form, and +the series collapses to + +$$ T(x,t) = \frac{T_0L\sqrt{\pi}}{M}\left\{\frac{1}{2} + \sum_{n=1}^{N}\cos\!\left(\frac{n\pi x}{M}\right)\exp\!\left[-\left(\frac{n\pi}{2M}\right)^2\!(4\kappa t+L^2)\right]\right\} . $$ + +The box is fictitious, so $M$ and $N$ are ours to choose, and a wrong choice shows up as an error +against the exact solution. Take $L=10$ m, $-3L0 . $$ + +The exponential is the kernel of the heat equation with $\kappa$ replaced by $1/(\sigma\mu)$, so the field soaks into the ground as heat spreads along a wire. The prefactor falls as $t^{-1/2}$. + +Every field in this lab has that form, $t^{-p}\exp(-\sigma\mu r^2/4t)$, with a different $p$. It is worth finding the peak time once, for any $p$. + +```{figure} figures/setup_sheet.svg +:name: fig-lab6-sheet +:width: 85% + +The model of this part. An infinite sheet of current switched on at $t=0$, in a uniform conductor, with receivers at three depths. +``` + +### Task 1 — when does the field arrive, and in what ground? + +Setting $\partial_t\ln|E|=0$ is easier than differentiating $|E|$ itself and gives the same answer. With a prefactor $t^{-p}$, + +$$ -\frac{p}{t} + \frac{\sigma\mu r^2}{4t^2} = 0 . $$ + +Solve it for $t$ and write the result once, as `t_peak(r, p, s)`. + +**Predict** before running, and sketch it: on one logarithmic time axis, draw $|E_x|(t)$ at 100 m and at 1000 m, each scaled to its own peak. Are the two curves the same shape, or does the deeper one spread out? Shifted by what factor? Then rank the same receiver in three grounds, seawater at 4 S/m, saturated sediments at $10^{-2}$ S/m and crystalline basement at $10^{-4}$ S/m, by arrival time. + +The second blank is the margin the diffusive approximation still has. Dropping $\varepsilon\,\partial_t\boldsymbol E$ is safe only while the peak arrives long after the charge relaxation time $\tau_r=\varepsilon/\sigma$. Write $t_p/\tau_r$ for the sheet in closed form, in terms of $z$ and $\sigma$, and watch what $\sigma$ does to it. + +Dividing by the value at the shallowest depth cancels the common $t^{-1/2}$ and leaves the bare kernel $\exp(-\sigma\mu z^2/4t)$: how far the field has reached, not how strong it is. That ratio only climbs and saturates, so look for the shoulder at $1/\sqrt e$, not a maximum. A receiver keeps the $t^{-1/2}$, and there the arriving exponential and the decaying prefactor compete. That competition is what $t_p$ solves. + +```{code-cell} ipython3 +sigma_sheet, eps_r, I_sheet = 0.01, 10.0, 1.0 # sediments [S/m], relative permittivity, [A/m] +tau_r = eps_r * epsilon_0 / sigma_sheet # charge relaxation time [s] + +def E_sheet(z, t, s=sigma_sheet): + """eq:ExtH -- the field of a current sheet switched on at t = 0 [V/m].""" + return -I_sheet * np.sqrt(mu / (4*np.pi*s*t)) * np.exp(-s*mu*z**2 / (4*t)) + +def t_for_D(D, s): + """When the diffusion distance sqrt(4t/(s*mu)) reaches D [s]. Used only to + frame the figures, so that every axis follows the parameters you set.""" + return s * mu * D**2 / 4 + +# Task 1 -- two blanks. +def t_peak(r, p, s): + """Time at which t**(-p) * exp(-s*mu*r**2/(4t)) is largest [s]. + Solve -p/t + s*mu*r**2/(4*t**2) = 0 for t.""" + return ___ + +def peak_over_relax(z, s): + """How many charge relaxation times the sheet's peak waits, t_p / tau_r. + The sheet has p = 1/2, and tau_r = eps_r*epsilon_0/s.""" + return ___ + +# --- given: the field soaking downward. Drag the bar, or press play --------- +z_grid = np.linspace(1.0, 2000.0, 400) # depth [m] +t_grid = np.logspace(np.log10(t_for_D(z_grid[-1], sigma_sheet)) - 4, + np.log10(t_for_D(z_grid[-1], sigma_sheet)), 60) # [s] +soak = np.array([np.abs(E_sheet(z_grid, tv)) / np.abs(E_sheet(z_grid[0], tv)) + for tv in t_grid]) +fw.show_profiles(z_grid, soak, t_grid, value_name="t", value_fmt="{:.2g}", unit=" s", log_x=True, + xlabel="depth z [m]", ylabel="|Ex| / its value at the surface", + title="The field diffuses into the Earth", ylim=(0.0, 1.05)) + +# --- given: depth against time, with your arrival-time curve over it -------- +fw.show_spacetime(z_grid, t_grid, soak, t_label="t [s]", x_label="depth z [m]", + c_label=r"$|E_x|$ / surface value", signed=False, + curve=(t_peak(z_grid, 0.5, sigma_sheet), z_grid), + curve_label=r"your $t_p(z)$", deeper_down=True, + title=r"$|E_x|$ against depth and time, with your $t_p(z)$ drawn over it") + +# --- given: what a receiver records at three depths ------------------------ +depths = [100.0, 300.0, 1000.0] # [m] +t_rec = np.logspace(np.log10(t_for_D(min(depths), sigma_sheet)) - 2, + np.log10(t_for_D(max(depths), sigma_sheet)) + 2, 3001) # [s] +fw.show_records(t_rec, {f"z = {z:g} m": np.abs(E_sheet(z, t_rec)) / np.max(np.abs(E_sheet(z, t_rec))) + for z in depths}, + peaks={f"z = {z:g} m": (t_peak(z, 0.5, sigma_sheet), 1.0) for z in depths}, + t_label="t [s]", y_label=r"$|E_x|$ / peak value", + title=f"Step response at depth, sigma = {sigma_sheet:g} S/m") + +_zc = depths[1] +fw.check_scalar(f"t_p at {_zc:g} m against the peak of the record", + t_peak(_zc, 0.5, sigma_sheet), + t_rec[np.argmax(np.abs(E_sheet(_zc, t_rec)))], rtol=0.01, unit=" s") +``` + +The same expression evaluated at three conductivities. $t_p$ is linear in $\sigma$ while $\tau_r=\varepsilon/\sigma$ is inverse in it, so those two move opposite ways and their ratio, the margin, carries $\sigma$ twice. A margin above about 100 is comfortable. + +```{code-cell} ipython3 +# --- given: one receiver at 300 m, three grounds --------------------------- +media = {"seawater, 4 S/m": 4.0, + "saturated sediments, 1e-2 S/m": 0.01, + "crystalline basement, 1e-4 S/m": 1e-4} +z_s = 300.0 # the receiver depth [m] +_tp_all = [t_peak(z_s, 0.5, sv) for sv in media.values()] +t_s = np.logspace(np.log10(min(_tp_all)) - 3, np.log10(max(_tp_all)) + 2, 900) + +fw.show_records(t_s, {k: np.abs(E_sheet(z_s, t_s, sv)) / np.max(np.abs(E_sheet(z_s, t_s, sv))) + for k, sv in media.items()}, + peaks={k: (t_peak(z_s, 0.5, sv), 1.0) for k, sv in media.items()}, + t_label="t [s]", y_label="|E| / peak value", + title=f"The same receiver at {z_s:.0f} m, in three grounds") + +print(f"at z = {z_s:.0f} m\n") +print(f"{'ground':<30}{'t_p [s]':>11}{'tau_r [s]':>11}{'t_p / tau_r':>13}") +for k, sv in media.items(): + print(f"{k:<30}{t_peak(z_s, 0.5, sv):>11.3g}{eps_r*epsilon_0/sv:>11.3g}" + f"{peak_over_relax(z_s, sv):>13.3g}") + +fw.check("a tenfold drop in conductivity costs a hundredfold in margin", + np.isclose(peak_over_relax(z_s, 1e-3) / peak_over_relax(z_s, 1e-4), 100.0, rtol=1e-9), + "the margin goes as sigma squared, not as sigma") +fw.check_scalar("the margin itself, against t_p and tau_r worked out separately", + peak_over_relax(z_s, sigma_sheet), + t_peak(z_s, 0.5, sigma_sheet) / (eps_r*epsilon_0/sigma_sheet), rtol=1e-6) +``` + +:::{admonition} Solution — Task 1 +:class: dropdown + +```python +def t_peak(r, p, s): + return s * mu * r**2 / (4 * p) + +def peak_over_relax(z, s): + return s**2 * mu * z**2 / (2 * eps_r * epsilon_0) +``` +::: + +:::{admonition} Depth maps onto arrival time, and conductivity sets the clock +:class: important dropdown + +A layer ten times deeper answers a hundred times later: 63 µs at 100 m, 6.3 ms at 1 km, for $\sigma=0.01$ S/m. Your curve runs along the shoulder of the diffusing field, because $|E_x|$ has fallen to $1/\sqrt e$ of its surface value exactly where $t=\sigma\mu z^2/2$. Time-domain electromagnetic soundings rest on this: the later part of a record senses the deeper Earth. + +At 300 m the peak arrives after 0.23 s in seawater, 0.57 ms in sediments and 5.7 µs in basement, a factor $4\times10^4$ from basement to seawater. That is exactly the ratio of the two conductivities, because $t_p=\sigma\mu z^2/2$ is linear in $\sigma$. A conductive ground holds the field up; a resistive one lets it through at once. + +The margin behaves differently. $\tau_r=\varepsilon/\sigma$ grows as the ground becomes resistive while $t_p$ shrinks, so + +$$ \frac{t_p}{\tau_r} = \frac{\sigma^2\mu z^2}{2\varepsilon} $$ + +carries $\sigma$ twice: $10^{10}$ in seawater, $6.4\times10^4$ in sediments, and **6.4** in basement. The diffusive approximation is comfortable in the first two and running out in the third, and it is the *resistive* ground that breaks it. Dropping $\varepsilon\,\partial_t\boldsymbol E$ was never a statement about depth. It is a statement about how fast charge can relax. +::: + +--- + +## Part 2 — Two dimensions: an infinite wire + +A long wire along $z$ carries a current switched on at $t=0$. Nothing depends on $z$, so the field lives in the $(x,y)$-plane: the electric field is $E_z$, perpendicular to that plane, and the magnetic field lies in it. This is the Transverse Electric mode of the lecture, and the chapter gives + +$$ E_z(\varrho,t) = -\frac{\mu I}{4\pi t}\exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right),\qquad \varrho=\sqrt{x^2+y^2}. $$ + +Negative, as the sheet's field was: the current is switched on, and the field it drives in the ground opposes it. + +The kernel is the same as the sheet's. The prefactor is now $t^{-1}$, so $p=1$. + +```{figure} figures/setup_wire.svg +:name: fig-lab6-wire +:width: 92% + +The model of this part. The wire is a point in the plane you will plot, the electric field points out of that plane, and the magnetic field circles the wire within it. +``` + +### Task 2 — the field of the wire, and when it arrives + +Write $E_z$. Then **predict**, before running: at the same distance, does the wire's field peak earlier or later than the sheet's, and by what factor? + +The colour is logarithmic and rescaled frame by frame. The kernel falls off so steeply that one linear scale would leave a bright spot and an empty plane, and the level drops as $1/t$ across the run, so a fixed scale would lose the late frames. + +```{code-cell} ipython3 +sigma_wire, I_wire = 3.0, 1.0 # seawater [S/m], wire current [A] + +# Task 2 -- one blank. +def E_wire(rho, t, s=sigma_wire): + """E_z of an infinitely long wire with a step switch-on current [V/m]. + Prefactor t**(-1), times the kernel exp(-s*mu*rho**2/(4t)). Opposes the + current, so it is negative.""" + return ___ + +# --- given: the field spreading out from the wire, on a logarithmic colour scale --- +n_w, half_w = 91, 50.0 +x_w = np.linspace(-half_w, half_w, n_w) # [m] +X_w, Y_w = np.meshgrid(x_w, x_w, indexing="ij") # F[ix, iy] sits at (x[ix], y[iy]) +rho_w = np.hypot(X_w, Y_w) +rho_w[rho_w == 0] = x_w[1] - x_w[0] # keep the wire out of the formula +# from a fifth of the box to twice it: past that the picture is uniform colour +t_w = np.logspace(np.log10(t_for_D(half_w / 5, sigma_wire)), + np.log10(t_for_D(half_w * 2, sigma_wire)), 16) # [s] + +E_frames = np.array([E_wire(rho_w, tv) for tv in t_w]) +fw.show_map(x_w, x_w, E_frames, t_w, value_name="t", value_fmt="{:.2g}", unit=" s", + x_label="x [m]", y_label="y [m]", c_label="log10(Ez / max)", + log_c=True, per_frame_scale=True, title="The electric field spreads out from the wire") + +# --- given: three receivers, with your arrival times marked ---------------- +dists = [0.36, 15.0, 30.0] # [m] +d_mid = dists[1] +t_r = np.logspace(np.log10(t_for_D(min(dists), sigma_wire)) - 2, + np.log10(t_for_D(max(dists), sigma_wire)) + 3, 3001) # [s] +fw.show_records(t_r, {f"{d:g} m": np.abs(E_wire(d, t_r)) / np.max(np.abs(E_wire(d, t_r))) for d in dists}, + peaks={f"{d:g} m": (t_peak(d, 1, sigma_wire), 1.0) for d in dists}, + t_label="t [s]", y_label=r"$|E_z|$ / peak value", + title=f"The wire, sigma = {sigma_wire:g} S/m:" + f" close in, the field is already fading") + +print(f"the sheet and the wire at the same {d_mid:g} m, in the same ground:") +print(f" sheet, p = 1/2 : t_p = {t_peak(d_mid, 0.5, sigma_wire)*1e3:.3f} ms") +print(f" wire, p = 1 : t_p = {t_peak(d_mid, 1.0, sigma_wire)*1e3:.3f} ms") + +_tpm = t_peak(d_mid, 1, sigma_wire) +fw.check_scalar(f"t_p at {d_mid:g} m against the peak of the record", _tpm, + t_r[np.argmax(np.abs(E_wire(d_mid, t_r)))], rtol=0.01, unit=" s") +fw.check_scalar("the peak value, against -mu I / (4 pi t_p) times 1/e", E_wire(d_mid, _tpm), + -mu*I_wire/(4*np.pi*_tpm)*np.exp(-1.0), rtol=0.01, unit=" V/m") +``` + +:::{admonition} Solution — Task 2 +:class: dropdown + +```python +def E_wire(rho, t, s=sigma_wire): + return -mu * I_wire / (4*np.pi*t) * np.exp(-s*mu*rho**2 / (4*t)) +``` +::: + +### Task 3 — the magnetic field climbs to its static value + +The wire's magnetic field circles it. Long after switch-on it must settle at the static result of the curl chapter, $\boldsymbol H = I\hat{\boldsymbol\varphi}/(2\pi\varrho)$. The chapter shows that it approaches that value through the same exponential that shapes $E_z$, with no power of $t$ in front: + +$$ \frac{|\boldsymbol H|}{|\boldsymbol H|_{\text{static}}} = \exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right),\qquad |\boldsymbol H|_{\text{static}} = \frac{I}{2\pi\varrho}. $$ + +Write that ratio. It runs from 0 at switch-on to 1 at late time, so the picture shows how far the field has got, not how strong it is. + +Then move the conductivity slider on the second figure. **Predict** first: in which ground does the magnetic field reach its static value soonest? + +```{code-cell} ipython3 +# Task 3 -- one blank. +def H_over_static(rho, t, s=sigma_wire): + """|H| divided by its static value. Dimensionless, 0 at switch-on and 1 at late time.""" + return ___ + +# --- given: the magnetic field filling in, with its direction --------------- +H_frames = np.array([H_over_static(rho_w, tv) for tv in t_w]) +Hx_dir = np.broadcast_to(-Y_w / rho_w, (len(t_w),) + rho_w.shape) # the unit vector phi-hat +Hy_dir = np.broadcast_to( X_w / rho_w, (len(t_w),) + rho_w.shape) +fw.show_map(x_w, x_w, H_frames, t_w, arrows=(Hx_dir, Hy_dir), arrow_every=10, + value_name="t", value_fmt="{:.2g}", unit=" s", zmin=0.0, zmax=1.0, + x_label="x [m]", y_label="y [m]", c_label="|H| / static value", + title="The magnetic field is already circular. It is only filling in") + +# --- given: how far it still has to go, over five conductivities ----------- +sigmas = np.array([0.01, 0.1, 1.0, 3.0, 10.0]) # [S/m] +# wide enough to show the 1/t tail for every curve, and no wider: far below this +# the exponential is zero to machine precision and nothing is left to plot +_a_lo = t_for_D(min(dists[1:]), sigmas.min()) +_a_hi = t_for_D(max(dists[1:]), sigmas.max()) +t_h = np.logspace(np.log10(_a_hi / 500), np.log10(_a_lo * 1e7), 400) # [s] +gap = {f"{d:g} m": np.array([1.0 - H_over_static(d, t_h, sv) for sv in sigmas]) + for d in dists[1:]} +fw.show_profiles(t_h, gap, sigmas, value_name="σ", value_fmt="{:.3g}", unit=" S/m", + xlabel="t [s]", ylabel="1 − |H| / static value", log_x=True, log_y=True, + title="How far the magnetic field still has to go, against time") + +# "early" and "late" written in terms of the problem, so the test survives a change +# of sigma_wire or of the distance: the field has spread a fifth of d_mid, then a hundred times it. +_early, _late = t_for_D(d_mid / 5, sigma_wire), t_for_D(d_mid * 100, sigma_wire) +fw.check("the ratio climbs from 0 at switch-on to 1 at late time", + H_over_static(d_mid, _early) < 1e-6 and abs(H_over_static(d_mid, _late) - 1.0) < 1e-3, + "it is exp(-a/t), not 1 - exp(-a/t): at t -> 0 there is no field yet") +# the shape alone does not pin the clock: a wrong factor in the exponent still +# climbs from 0 to 1. This fixes when, using the t_p you already wrote. +fw.check_scalar("|H| is at 1/e of static exactly at the wire's own peak time", + H_over_static(d_mid, t_peak(d_mid, 1, sigma_wire)), np.exp(-1.0), rtol=1e-6) +``` + +:::{admonition} Solution — Task 3 +:class: dropdown + +```python +def H_over_static(rho, t, s=sigma_wire): + return np.exp(-s*mu*rho**2 / (4*t)) +``` +::: + +### Task 4 — while it diffuses, the magnetic field has curl + +The chapter's two-dimensional equation that connects the fields to the source is $-\partial_xH_y+\partial_yH_x+\sigma E_z=0$ away from the wire, which is Ampère's law, $\nabla\times\boldsymbol H=\sigma\boldsymbol E$, in two dimensions. The curl of $\boldsymbol H$ is not an abstraction here: it is the electric field, times $\sigma$. As $E_z$ dies the curl dies with it, and the magnetic field becomes a potential field. + +Write the $z$-component of the curl. The two derivatives of each component are already computed for you. + +With no source this says $\partial_xH_y-\partial_yH_x=\sigma E_z$, and both sides are negative because $E_z$ is. Where the two pictures agree, the diffusing magnetic field is demonstrably not curl-free. Near the wire they will not agree, because a finite grid cannot follow $1/\varrho$. + +```{code-cell} ipython3 +# One instant, chosen so the field has spread about as far as the ring the check uses. +# That makes the accuracy below independent of sigma_wire. +r_ring = (0.4*half_w, 0.9*half_w) # the comparison ring [m] +t_c = t_for_D(np.mean(r_ring), sigma_wire) # [s] +dx = x_w[1] - x_w[0] +H_mag = I_wire / (2*np.pi*rho_w) * H_over_static(rho_w, t_c) +Hx_c, Hy_c = -Y_w/rho_w * H_mag, X_w/rho_w * H_mag # [A/m] + +dHx_dx, dHx_dy = np.gradient(Hx_c, dx, dx) # indexing='ij', so [0] is d/dx +dHy_dx, dHy_dy = np.gradient(Hy_c, dx, dx) + +# Task 4 -- one blank: the z-component of the curl of H. +curl_z = ___ + +# --- given: the curl beside the electric field it equals ------------------- +shown = rho_w > 7*dx # H goes as 1/rho, so the grid cannot follow it at the wire +fw.show_map(x_w, x_w, np.array([np.where(shown, curl_z, np.nan), + np.where(shown, sigma_wire*E_wire(rho_w, t_c), np.nan)]), + ["curl of H", "sigma times E_z"], value_name="showing", value_fmt="{}", + x_label="x [m]", y_label="y [m]", c_label="A/m²", + title=f"Two ways to the same picture, at t = {t_c*1e3:g} ms") + +# The comparison is made on the outer ring, where the grid resolves 1/rho. Push t_c +# up and it will fail: the true curl is on its way to zero, and round-off takes over. +ring = (rho_w > r_ring[0]) & (rho_w < r_ring[1]) +fw.check_close("the curl of H against sigma E_z, away from the wire", + curl_z[ring], sigma_wire*E_wire(rho_w, t_c)[ring], rtol=0.05, + hint="Ampere with no source: d_x H_y - d_y H_x = sigma E_z") +``` + +:::{admonition} Solution — Task 4 +:class: dropdown + +```python +curl_z = dHy_dx - dHx_dy +``` +::: + +:::{admonition} The wire answers twice as fast as the sheet, and the curl dies with the electric field +:class: important dropdown + +At 15 m in seawater the sheet peaks at 0.42 ms and the wire at 0.21 ms, a factor of two, because $t_p=\sigma\mu r^2/4p$ and $p$ went from $1/2$ to $1$. A steeper prefactor pulls the peak earlier: the field is being drained faster, so the moment at which arrival stops winning over decay comes sooner. + +The two magnetic pictures say different things. The map never changes shape, because the direction $\hat{\boldsymbol\varphi}$ is circular from the first instant and only the amount fills in. What takes time is the *amount*, and the second figure shows how far there is still to go. Expanding the exponential for $t\gg\sigma\mu\varrho^2/4$, + +$$ 1 - \exp\left(-\frac{\sigma\mu\varrho^2}{4t}\right) \approx \frac{\sigma\mu\varrho^2}{4t}, $$ + +so the gap closes as $1/t$, which is the straight line of slope $-1$ on the logarithmic axes. A conductive ground is slower, and doubling the distance costs a factor of four in waiting. + +The curl map is the electric field map, rescaled. That is {eq}`eq:TEEy` read as a picture, and it is the sharpest statement of what makes a diffusive field different from a static one: the static magnetic field of the curl chapter is curl-free outside the wire, and this one is not, for exactly as long as there is an electric field to drive it. Let $t$ run on and both die, which is why the chapter says the magnetic field becomes a potential field at infinite time. +::: + +--- + +## Part 3 — Three dimensions, and one law for all of them + +A point source in three dimensions has the impulse response {eq}`eq:G3D`, + +$$ G(R,t) = \frac{(\sigma\mu)^{1/2}}{[4\pi t]^{3/2}}\exp\left(-\frac{\sigma\mu R^2}{4t}\right). $$ + +Same kernel again. The prefactor is $t^{-3/2}$, so $p=3/2$. + +```{figure} figures/setup_ladder.svg +:name: fig-lab6-ladder +:width: 95% + +The three models of this lab side by side. The source spreads over a plane, a cylinder or a sphere, which is the only thing that changes between them. +``` + +### Task 5 — the ladder + +Write $G$. Your `t_peak` already covers it: the three geometries differ only in $p$, so at the same distance their peak times are in a fixed ratio. **Predict** that ratio before you run the last figure. Then one the formula does not hand you: which of the three records is the broadest on a logarithmic time axis, and which has the slowest tail? Say why before you look. + +```{code-cell} ipython3 +sigma_pt = 0.01 # sediments [S/m] + +# Task 5 -- one blank. +def G_point(R, t, s=sigma_pt): + """eq:G3D -- the impulse response in three dimensions [1/(m s)].""" + return ___ + +# --- given: a rotatable view of the field at one instant ------------------- +# The box is sized from the field, so changing t_show rescales both together: +# the shell keeps its size on screen and the axis numbers change instead. +t_show = 1.0e-3 # [s] +D_show = np.sqrt(4*t_show / (sigma_pt*mu)) # how far it has spread [m] +g_xy = np.linspace(-1.8*D_show, 1.8*D_show, 32) # the box follows the field +g_z = np.linspace(0.0, 1.8*D_show, 32) # depth [m] +GX, GY, GZ = np.meshgrid(g_xy, g_xy, g_z, indexing="ij") +G_vol = G_point(np.sqrt(GX**2 + GY**2 + GZ**2), t_show) +fw.show_isosurface(g_xy, g_xy, g_z, G_vol, levels=(0.08, 0.25, 0.6), opacity=0.32, + c_label="G", z_label="depth z [m]", + title=f"The point source at t = {t_show*1e3:g} ms. Drag to rotate") + +# --- given: the three geometries at the same distance, same ground --------- +r0 = 300.0 # [m] +t_l = np.logspace(np.log10(t_for_D(r0, sigma_pt)) - 2, + np.log10(t_for_D(r0, sigma_pt)) + 2, 4001) # [s] +ladder = {"sheet, p = 1/2": np.abs(E_sheet(r0, t_l, sigma_pt)), + "wire, p = 1 ": np.abs(E_wire(r0, t_l, sigma_pt)), + "point, p = 3/2": G_point(r0, t_l)} +fw.show_records(t_l, {k: v / np.max(v) for k, v in ladder.items()}, + peaks={k: (t_peak(r0, p, sigma_pt), 1.0) + for k, p in zip(ladder, (0.5, 1.0, 1.5))}, + t_label="t [s]", y_label="field / its own peak", + title=f"The same {r0:.0f} m in the same ground, three geometries") + +print(f"{'geometry':<12}{'p':>6}{'t_p [ms]':>12}{'ratio':>8}") +for name, p in zip(("sheet", "wire", "point"), (0.5, 1.0, 1.5)): + tp = t_peak(r0, p, sigma_pt) + print(f"{name:<12}{p:>6}{tp*1e3:>12.3f}{tp/t_peak(r0, 1.5, sigma_pt):>8.1f}") + +fw.check_scalar("the point source peaks at sigma mu R^2 / 6", + t_peak(r0, 1.5, sigma_pt), t_l[np.argmax(G_point(r0, t_l))], + rtol=0.01, unit=" s") +# integrate out to ten diffusion distances, where the Gaussian has nothing left +_R = np.linspace(1e-3, 10*D_show, 60000) # a radial grid [m] +fw.check_scalar("the integral of G over all space, which fixes the constant in front", + np.sum(G_point(_R, t_show) * 4*np.pi*_R**2) * (_R[1] - _R[0]), + 1.0 / (sigma_pt*mu), rtol=0.01, unit=" m^2/s") +``` + +:::{admonition} Solution — Task 5 +:class: dropdown + +```python +def G_point(R, t, s=sigma_pt): + return np.sqrt(s*mu) / (4*np.pi*t)**1.5 * np.exp(-s*mu*R**2 / (4*t)) +``` +::: + +:::{admonition} The ladder, and why the sphere answers first +:class: important dropdown + +$$ t_p = \frac{\sigma\mu r^2}{4p}:\qquad \frac{\sigma\mu r^2}{2},\quad \frac{\sigma\mu r^2}{4},\quad \frac{\sigma\mu r^2}{6} $$ + +for $p=\tfrac12,1,\tfrac32$. The three peak times are in the ratio **6 : 3 : 2**, whatever the distance and whatever the ground, because the kernel is identical and only the prefactor differs. At 300 m in sediments that is 0.57 ms, 0.28 ms and 0.19 ms. + +The reason is worth saying in words. The exponential is the arrival: it rises from nothing as the diffusing field reaches $r$, and it does not care about the geometry. The prefactor is the decay: it is how fast the energy is spreading out, over a line, a cylinder or a sphere. The peak is where the two balance, so a geometry that spreads faster peaks earlier. The sphere spreads fastest, and answers first. + +The three-dimensional amplitude falls as $1/R^3$: double the distance and the peak is eight times smaller, against four for the wire and two for the sheet. Volume is expensive. +::: + +--- + +## Part 4 — A loop on the surface + +A real transmitter is a loop, not an infinite wire. A square loop of side $L_x=L_y=100$ m lies on the surface and its current is switched on at $t=0$. Integrating the three-dimensional Green's function along the four segments gives {eq}`eq:Exloop` and {eq}`eq:Eyloop`: + +$$ E_y(\boldsymbol r,t) = -\frac{\mu}{8\pi t}\left\{\exp\left(-\frac{x_m^2+z^2}{D^2}\right) - \exp\left(-\frac{x_p^2+z^2}{D^2}\right)\right\}\left[\mathrm{erf}\left(\frac{y_p}{D}\right) - \mathrm{erf}\left(\frac{y_m}{D}\right)\right] $$ + +with $x_p=x+L_x/2$, $x_m=x-L_x/2$, and the **diffusion distance** + +$$ D = \sqrt{\frac{4t}{\sigma\mu}} , $$ + +which is how far the field has spread by time $t$. The two exponentials are the two segments that run along $y$, at $x=\pm L_x/2$. They carry opposite currents, so they enter with opposite signs, and that difference is the only part you have to write. + +```{figure} figures/setup_loop.svg +:name: fig-lab6-loop +:width: 88% + +The model of this part, and the two planes you will cut through it. The current runs clockwise from vertex 1 to vertex 4, seen from above with $z$ pointing down. +``` + +### Task 6 — the loop forgets its shape + +Fill in the brace of $E_y$. Each of the three figures that follow then asks you one question, posed just above it. + +Integrating the point response along the four sides leaves a Gaussian across each pair of parallel wires and an error function along them. In the vertical plane through the middle of the loop you see the two segments that run along $y$, entering with opposite signs because they carry opposite currents. + +```{code-cell} ipython3 +sigma_loop, Lx, Ly = 0.3, 100.0, 100.0 # [S/m], loop sides [m] + +def D_of(t, s=sigma_loop): + """The diffusion distance [m]: how far the field has spread by time t.""" + return np.sqrt(4*t / (s*mu)) + +def Ex_loop(x, y, z, t, s=sigma_loop): + """eq:Exloop -- given, as the pattern to follow [V/m].""" + D = D_of(t, s) + xp, xm = x + Lx/2, x - Lx/2 # to the two segments that run along y + yp, ym = y + Ly/2, y - Ly/2 # to the two segments that run along x + return (-mu / (8*np.pi*t) + * (np.exp(-(yp**2+z**2)/D**2) - np.exp(-(ym**2+z**2)/D**2)) + * (erf(xp/D) - erf(xm/D))) + +# Task 6 -- one blank. eq:Eyloop is eq:Exloop with x and y exchanged, except +# that the two exponentials come in the opposite order, because the two +# segments at x = +-Lx/2 carry opposite currents. +def Ey_loop(x, y, z, t, s=sigma_loop): + """eq:Eyloop [V/m].""" + D = D_of(t, s) + xp, xm = x + Lx/2, x - Lx/2 + yp, ym = y + Ly/2, y - Ly/2 + return ___ + +def E_loop(x, y, z, t, s=sigma_loop): + """Both horizontal components, as a pair.""" + return Ex_loop(x, y, z, t, s), Ey_loop(x, y, z, t, s) + +# --- given: the vertical plane through the middle of the loop -------------- +n_L = 91 +x_L = np.linspace(-3*Lx, 3*Lx, n_L) # three loop widths either way [m] +z_L = np.linspace(0.0, 3*Lx, n_L) +XZ_x, XZ_z = np.meshgrid(x_L, z_L, indexing="ij") +# from when the field has spread a tenth of the loop to when it has spread ten times it +t_L = np.logspace(np.log10(t_for_D(Lx/10, sigma_loop)), + np.log10(t_for_D(Lx*10, sigma_loop)), 16) # [s] + +xz = np.array([E_loop(XZ_x, 0.0, XZ_z, tv)[1] for tv in t_L]) +fw.show_map(x_L, z_L, xz, t_L*1e3, value_name="t", value_fmt="{:.3g}", unit=" ms", + x_label="x [m]", y_label="depth z [m]", c_label="Ey [V/m]", + per_frame_scale=True, y_down=True, equal_aspect=False, + title="Two lobes of opposite sign, over the two wires, moving apart and down") +``` + +The same field, finely sampled, from the lecturer's own script. It runs over 200 instants instead of the 16 on your slider. + +```{video} figures/ELoopwsxz.mp4 +:width: 80% +``` + +The diffusion distance $D=\sqrt{4t/\sigma\mu}$ is the only length the field itself carries. Holding it against $L_x$ is what decides whether the pattern still remembers the shape of its source. + +**Question 1.** Drag the slider, which carries $D$. At which $D$ does the square stop looking square? Compare it with $L_x$. + +```{code-cell} ipython3 +# --- given: the plane at 10 m depth, seen from above. Arrows give direction --- +z_xy = 10.0 # the depth of this slice [m] +# its own narrower grid: the question is about the shape of the loop, and at +# three loop widths either way the square is only a dozen pixels across +x_xy = np.linspace(-1.5*Lx, 1.5*Lx, n_L) # [m] +XY_x, XY_y = np.meshgrid(x_xy, x_xy, indexing="ij") +EE = [E_loop(XY_x, XY_y, z_xy, tv) for tv in t_L] +mag = np.array([np.hypot(ex, ey) for ex, ey in EE]) +# the slider carries D, not t, because the question is about D against Lx +fw.show_map(x_xy, x_xy, mag, D_of(t_L), + arrows=(np.array([e[0] for e in EE]), np.array([e[1] for e in EE])), + arrow_every=10, log_c=True, per_frame_scale=True, y_down=True, + value_name="D", value_fmt="{:.0f}", unit=f" m (Lx = {Lx:g} m)", + x_label="x [m]", y_label="y [m]", c_label="log10(|E| / max)", + title=f"At z = {z_xy:g} m, seen from above") + +print(f"{'t [ms]':>9}{'D [m]':>9}{'D / Lx':>9}") +for tv in t_L[::3]: + print(f"{tv*1e3:>9.3g}{D_of(tv):>9.1f}{D_of(tv)/Lx:>9.2f}") +``` + +Now time is held fixed and depth is stepped instead, with one colour scale shared by every frame so they can be compared directly. + +**Question 2.** Before you run it, write down with a neighbour what each of you expects to change as $z$ grows: the brightness, the width of the pattern, the direction of the arrows, or the position of the maximum. You will disagree about at least one of those. Run the cell, then settle it from {eq}`eq:Eyloop` rather than from the picture. + +```{code-cell} ipython3 +# --- given: the same instant, at a depth you choose ------------------------- +t_fix = 3e-4 # [s] +# depths spaced against the diffusion distance, so the frames always span the drop +# and stay inside the colour floor of 1e-4 that show_map clips at +z_try = np.round(D_of(t_fix) * np.array([0.0, 0.6, 1.2, 1.8, 2.4])) # depth [m] +deep = np.array([np.hypot(*E_loop(XY_x, XY_y, zv, t_fix)) for zv in z_try]) +fw.show_map(x_xy, x_xy, deep, z_try, value_name="z", value_fmt="{:.0f}", unit=" m", + log_c=True, per_frame_scale=False, y_down=True, + x_label="x [m]", y_label="y [m]", c_label="log10(|E| / max)", + title=f"The same instant, t = {t_fix*1e3:g} ms, at {len(z_try)} depths") + +print(f"at t = {t_fix*1e3:g} ms the diffusion distance is D = {D_of(t_fix):.0f} m\n") +print(f"{'depth [m]':>11}{'|E| / its surface value':>26}") +for zv in z_try: + f = np.exp(-zv**2 / D_of(t_fix)**2) + print(f"{zv:>11.0f}{f:>26.4f}") +``` + +Nested surfaces of constant $|\boldsymbol E|$ on a cube around the loop, so the interior stays visible. The box is sized from $D$ and keeps framing the field at whatever instant you set. + +**Question 3.** Rotate it, then set `t_3d = 3e-4` and run again. What has happened to the loop relative to the field it is driving? + +```{code-cell} ipython3 +# --- given: the loop in three dimensions. Drag to rotate -------------------- +t_3d = 3e-5 # [s] +# wide enough for the loop, and for the field once it has spread past it +half3 = max(1.8*Lx/2, 1.5*D_of(t_3d)) # [m] +g3 = np.linspace(-half3, half3, 36) +gz3 = np.linspace(0.0, half3, 36) # depth [m] +L3x, L3y, L3z = np.meshgrid(g3, g3, gz3, indexing="ij") +E3x, E3y = E_loop(L3x, L3y, L3z, t_3d) +loop_wire = ([-Lx/2, Lx/2, Lx/2, -Lx/2, -Lx/2], + [-Ly/2, -Ly/2, Ly/2, Ly/2, -Ly/2], [0, 0, 0, 0, 0]) +fw.show_isosurface(g3, g3, gz3, np.hypot(E3x, E3y), levels=(0.06, 0.18, 0.45), opacity=0.3, + wire=loop_wire, wire_name="the loop", c_label="|E| [V/m]", + z_label="depth z [m]", + title=f"t = {t_3d*1e3:g} ms: D = {D_of(t_3d):.0f} m, " + f"D / Lx = {D_of(t_3d)/Lx:.2f}") + +fw.check("the field opposes the source current over the x = +Lx/2 wire", + E_loop(Lx/2, 0.0, z_xy, t_3d)[1] < 0 < E_loop(-Lx/2, 0.0, z_xy, t_3d)[1], + "the current there runs in +y, so an opposing field has E_y < 0") +# A square loop is unchanged by exchanging x and y, and the circulation reverses +# under that exchange, so E_y(x, y) = -E_x(y, x). This catches an erf bracket left +# running over the wrong coordinate, which the sign check above does not. +_q = np.array([-1.6, -0.4, 0.0, 0.7, 2.4]) * Lx +_QX, _QY = np.meshgrid(_q, _q, indexing="ij") +fw.check_close("E_y(x, y) against -E_x(y, x), which a square loop must satisfy", + Ey_loop(_QX, _QY, z_xy, t_3d), -Ex_loop(_QY, _QX, z_xy, t_3d), rtol=1e-9, + hint="the erf bracket of E_y must run over y, as its exponentials run over x") +``` + +:::{admonition} Solution — Task 6 +:class: dropdown + +```python +def Ey_loop(x, y, z, t, s=sigma_loop): + D = D_of(t, s) + xp, xm = x + Lx/2, x - Lx/2 + yp, ym = y + Ly/2, y - Ly/2 + return (-mu / (8*np.pi*t) + * (np.exp(-(xm**2+z**2)/D**2) - np.exp(-(xp**2+z**2)/D**2)) + * (erf(yp/D) - erf(ym/D))) +``` +::: + +:::{admonition} What time does to the pattern, and what depth does +:class: important dropdown + +**The square survives while $D$ is small.** At $t=0.01$ ms, $D=10$ m against a 100 m loop and the four wires are separate bright lines. By $t=0.1$ ms, $D=33$ m, and the pattern is already round. The loop stops looking square at about $D\approx L_x/3$, which is $t\approx\sigma\mu L_x^2/36$, here 0.1 ms. After that no measurement can tell this loop from a round one of the same area. A source forgets its shape once the field has diffused further than the source is big, and this is the same blurring that merged two Gaussians in the last lab. + +**Depth only dims it.** Put $z$ into {eq}`eq:Eyloop` and the depth appears as $\exp[-(x_m^2+z^2)/D^2]$, which factors into $\exp(-z^2/D^2)$ times the surface expression, identically for both components. So + +$$ \boldsymbol E(x,y,z,t) = \exp\left(-\frac{z^2}{D^2}\right)\boldsymbol E(x,y,0,t). $$ + +Going deeper multiplies the whole picture by one number. It does not blur it, does not rotate it, does not change which way the arrows point. The frames of the depth figure are the same image at different brightnesses, and the printed column is that one factor. + +That factor is the whole of depth sounding. At $t=0.3$ ms, $D=56$ m, so 50 m down you still have 46% of the surface field and 200 m down you have $3.5\times10^{-6}$ of it. You can only see about as deep as $D$, and $D$ grows as $\sqrt t$. To look twice as deep you must wait four times as long, which is Part 1's $t_p\propto z^2$ arriving from the other direction. + +**The arrows oppose the current.** Over the wire at $x=+L_x/2$ the current runs in $+\hat{\boldsymbol y}$ and $E_y$ is negative. The switched-on current drives a field that opposes it, which is Lenz's law seen in a conductor. +::: + +--- + +## Part 5 — Designing a sounding + +You now have everything a time-domain electromagnetic survey rests on. This part asks you to put it together. Answer the four questions first, from the formulas and not from a new calculation, then run the cell. + +1. A target lies 400 m down in ground of conductivity $10^{-2}$ S/m. Roughly when does the response from that depth arrive? Which $p$ did you put into `t_peak`, and does the choice matter at the factor-of-two level? +2. Your recording window is 20 µs to 10 ms. Which of the three grounds of Part 1 puts a 400 m target inside that window? +3. You have two loops, 50 m and 400 m on a side. The target is 400 m down. Which do you choose, and what decides it: the loop size, or the time you record for? +4. The field at the target is $\exp(-z^2/D^2)$ of its surface value. Below which amplitude would you say the target is not being illuminated at all, and what does that make the deepest usable depth? + +Question 3 is the one worth arguing about, because the intuitive answer is wrong and nothing on the page has told you otherwise yet. Commit to a loop before you run the second cell, which measures both. + +Everything here is $\exp(-z^2/D^2)$ at the target depth, with $D$ built from each ground's conductivity, against time. A target is worth looking for where that curve is still high inside the window you can actually record in. + +```{code-cell} ipython3 +# --- given: the window, the ground and the depth, all on one picture ------- +z_target = 400.0 # [m] +t_win = (2e-5, 1e-2) # the recording window [s] +_tp_t = [t_peak(z_target, 0.5, sv) for sv in media.values()] +t_d = np.logspace(min(np.log10(min(_tp_t)), np.log10(t_win[0])) - 2, + max(np.log10(max(_tp_t)), np.log10(t_win[1])) + 2, 2001) + +fig, ax = plt.subplots(figsize=(8.2, 3.6)) +for k, (name, sv) in enumerate(media.items()): + ax.plot(t_d, np.exp(-z_target**2 * sv * mu / (4*t_d)), color=f"C{k}", lw=2, label=name) + ax.axvline(t_peak(z_target, 0.5, sv), color=f"C{k}", ls=":", lw=1.2) +ax.axvspan(*t_win, color="0.85", zorder=0, label="recording window") +ax.axhline(1/np.e, color="k", lw=0.8, ls="--") +ax.text(0.01, 1/np.e + 0.02, "z = D", fontsize=8, transform=ax.get_yaxis_transform()) +ax.set_xscale("log"); ax.set_xlabel("t [s]") +ax.set_ylabel(f"illumination at {z_target:.0f} m, exp(-z²/D²)") +ax.set_title(f"Which ground puts a {z_target:.0f} m target inside the window?") +ax.grid(alpha=0.3); ax.legend(fontsize=8, loc="upper left") +plt.show() + +print(f"a target at {z_target:.0f} m, window {t_win[0]*1e6:.0f} us to {t_win[1]*1e3:.0f} ms\n") +print(f"{'ground':<30}{'t_p [s]':>11}{'in window?':>12}" + f"{f'illum. at {t_win[1]*1e3:g} ms':>18}") +for name, sv in media.items(): + tp = t_peak(z_target, 0.5, sv) + lit = np.exp(-z_target**2 * sv * mu / (4*t_win[1])) + print(f"{name:<30}{tp:>11.3g}{'yes' if t_win[0] < tp < t_win[1] else 'no':>12}{lit:>18.3g}") +``` + +Now the loop itself, the one you built in Part 4, at two sizes. Both are placed over the same target in the same ground, so the only thing different is the side length. + +```{code-cell} ipython3 +# --- given: a 50 m loop and a 400 m loop over the same target -------------- +_t_scan = np.logspace(-5, -1, 400) # [s] +_Lx0, _Ly0 = Lx, Ly # keep your Part 4 loop +for _L in (50.0, 400.0): + Lx = Ly = _L # E_loop reads these + _E = np.array([np.hypot(*E_loop(100.0, 0.0, z_target, tv, s=0.01)) for tv in _t_scan]) + print(f"L = {_L:3.0f} m: peak |E| = {_E.max():.2e} V/m at t = {_t_scan[_E.argmax()]*1e3:5.2f} ms," + f" D there = {np.sqrt(4*_t_scan[_E.argmax()]/(0.01*mu)):.0f} m") +Lx, Ly = _Lx0, _Ly0 + +print(f"\nthe loop's own arrival, t_p with p = 5/2 at R = sqrt(100^2 + {z_target:.0f}^2):" + f" {t_peak(np.hypot(100.0, z_target), 2.5, 0.01)*1e3:.2f} ms") +``` + +:::{admonition} Answers +:class: dropdown + +**1.** $t_p=\sigma\mu z^2/4p$. The sheet's $p=1/2$ gives 1.0 ms, the wire 0.50 ms, the point source 0.34 ms, and the loop's $p=5/2$ gives 0.20 ms. A survey uses a loop, so 0.2 ms is the honest number, but any of them sets the scale: the spread is a factor of five across geometries that differ completely. What matters is $t\sim\sigma\mu z^2$, not the number in the denominator. + +**2.** Sediments, at 1.0 ms, sit comfortably inside, and the printed table says so. Seawater peaks at 0.40 s, forty times beyond the end of the window: the window closes long before the response from 400 m arrives. Basement peaks at 10 µs, which is before the window opens, so its response from 400 m is already over by the time the first sample is taken. Only the middle ground is workable, and that is typical. + +**3.** The time you record for. Depth of investigation is set by $D=\sqrt{4t/\sigma\mu}$, which contains no loop size at all, and the cell measures what an eightfold change in $L$ actually does to the arrival: the peak moves from 0.215 ms to 0.271 ms and the diffusion distance at the peak from 262 m to 294 m. That is 26% and 12%, against a factor of 8 in the loop. The 50 m loop lands on $t_p$ with $p=5/2$ at $R=\sqrt{100^2+400^2}$, 0.214 ms, because at that size it is already a point as far as the target is concerned; the 400 m loop is the later of the two because the target now sits under the middle of it rather than off to one side. What the big loop buys is amplitude, a factor of 34 at the target, and that decides whether you can detect the response rather than where the response comes from. A bigger loop is worth having for exactly that reason, and for no other. You buy depth with late time and a quiet receiver. + +**4.** Any threshold in the range 1% to 10% gives nearly the same rule, because the Gaussian is so steep. Taking $1/e$ gives $z_{\max}=D=\sqrt{4t/\sigma\mu}$ exactly, which is the standard definition of the diffusion depth. Read the two ends of the window off the printed column. At the 1.0 ms peak in sediments $D=564$ m, so the 400 m target sits at $\exp(-0.50)=0.60$ of the surface field; by the 10 ms end of the window $D$ has grown to 1784 m and the target is at 0.95, which is what the table prints. In seawater 10 ms gives only $D=89$ m and the target is at $2\times10^{-9}$, which is nothing at all. Illumination is not what limits you in sediments; signal strength is. +::: + +:::{admonition} What this lab was about +:class: important dropdown + +One kernel, $\exp(-\sigma\mu r^2/4t)$, appeared in every part. It came from the heat equation last week with $\kappa$ replaced by $1/(\sigma\mu)$, and the only thing that changed from a sheet to a wire to a point was the power of $t$ in front, which is a statement about geometry and not about electromagnetism. + +From that one kernel came three results a geophysicist uses directly. Arrival time measures distance, $t_p=\sigma\mu r^2/4p$. Depth of investigation is the diffusion distance, $z\approx D=\sqrt{4t/\sigma\mu}$, and it is bought with time rather than with equipment. And a source is blurred into a point once $D$ exceeds its size, which is why the shape of a transmitter stops mattering, and also why deep structure is always seen blurred. + +The magnetic field made the fourth point. For as long as the electric field is there, $(\nabla\times\boldsymbol H)_z=\sigma E_z$ is not zero, and the magnetic field is not a potential field. It becomes one only in the limit, which is where the magnetostatics of the earlier chapters lives. +::: diff --git a/book/4_mechanical_waves/acoustic_waves.md b/book/4_mechanical_waves/acoustic_waves.md new file mode 100644 index 0000000..16ca9fa --- /dev/null +++ b/book/4_mechanical_waves/acoustic_waves.md @@ -0,0 +1,64 @@ +# Wave fields in a fluid: acoustic (P) waves + +With acoustic waves, we assume a fluid in which no shear forces exist, and therefore only P-waves exist. Since waves are physical phenomena, they should have a relation to basic physical laws. The two laws applicable are the conservation of mass and Newton's second law. These two have been used in [the appendix on 1-D acoustic wave motion](./appendix_acoustic_1d.md) to derive the two equations governing the wave motion due to a P-wave. There are some simplifying assumptions in the derivation, one of them being that we consider a 1-dimensional wave. When we denote $p$ as the pressure and $v_x$ as the particle velocity, the conservation of mass leads to: + +$$ +- \frac{1}{K} \frac{\partial p}{\partial t} = \frac{\partial v_x}{\partial x} +$$ (eq:eqdeform) + +in which $K$ is called the bulk modulus. The other relation follows from an application of Newton's law: + +$$ +-\frac{\partial p}{\partial x} = \rho \frac{\partial v_x}{\partial t} +$$ (eq:eqmotion) + +where $\rho$ denotes the mass density. This equation is called the equation of motion. + +We are now going to combine these two equations. Therefore, we let the operator $\partial / \partial x$ work on the equation of motion: + +$$ +- \frac{\partial}{\partial x} \left( \frac{\partial p}{\partial x} \right) + = + \frac{\partial}{\partial x} + \left( \rho \frac{\partial v_x}{\partial t} \right). +$$ (eq:diffeqmotion) + +Now, assuming $\rho$ is constant, it can be taken in front of the $\partial / \partial x$ operator. And differentiations with respect to space $x$ and time $t$ are commutative, so: + +$$ + \frac{\partial}{\partial x} \left( \frac{\partial v_x}{\partial t} \right) + = + \frac{\partial}{\partial t} \left( \frac{\partial v_x}{\partial x} \right). +$$ (eq:commut) + +Now for $\partial v_x / \partial x$, the conservation of mass can be substituted in {eq}`eq:diffeqmotion` to give: + +$$ + -\frac{\partial^2 p}{\partial x^2} = \rho + \frac{\partial}{\partial t} + \left( - \frac{1}{K} \frac{\partial p}{\partial t} \right). +$$ + +Rewriting gives us the 1-Dimensional wave equation: + +$$ +\frac{\partial^2 p}{\partial x^2} + - \frac{1}{c^2} \frac{\partial^2p}{\partial t^2} = 0 +$$ + +in which $c$ can be seen as the velocity of the wave, for which we have: $c = \sqrt{K/ \rho}$. + +This is the basic wave equation for one-dimensional acoustic waves. Equally well, we can derive from the same two equations {eq}`eq:eqdeform` and {eq}`eq:eqmotion` (see also the [*EXERCISES*](./exercises.md)) that the particle velocity also satisfies the wave equation: + +$$ +\frac{\partial^2 v_x}{\partial x^2} + - \frac{1}{c^2} \frac{\partial^2 v_x}{\partial t^2} = 0 +$$ (eq:waveqacv) + +where $c$ is the same as in the wave equation of the pressure. + +Actually, the movie we showed before was generated using the above equations (but then discretized), so the equation of deformation {eq}`eq:eqdeform` and the equation of motion {eq}`eq:eqmotion`. It is shown again below. + +```{video} figures/seismicwave_1layer_vz.mp4 +:width: 80% +``` diff --git a/book/4_mechanical_waves/appendix_acoustic_1d.md b/book/4_mechanical_waves/appendix_acoustic_1d.md new file mode 100644 index 0000000..1ad1193 --- /dev/null +++ b/book/4_mechanical_waves/appendix_acoustic_1d.md @@ -0,0 +1,76 @@ +(app-waveq1d)= +# Appendix: derivation of basic equations for 1-D acoustic wave motion + +*In this appendix, the one-dimensional wave motion for an acoustic medium is derived, starting from the deformation law of Hooke and from conservation of momentum (Newton's Second Law). This results in the so-called deformation equation and the equation of motion for acoustic waves.* + +## Derivation + +Here we will derive the basic equations for wave motion in homogeneous media, using the conservation of momentum (Newton's second law) and the deformation law, known as Hooke's Law of elasticity. In this derivation, we consider a single cube of mass when it is subdued to a seismic disturbance (see {numref}`fig-cube`). This cube has a volume $\Delta V$ with sides $\Delta X, \Delta Y$ and $\Delta Z.$ + +```{figure} figures/fig_ap_ac_cube.png +:name: fig-cube +:width: 70% + +A cube of mass, subjected to one-dimensional wave motion. Drawn line: original status. Dotted line: status after deformation. +``` + +We start with an elastic deformation of the cube, using Hooke's Law. This law states that the deformation force that works on a piece of material is linearly related to the extension of that piece. Applying this to our cube of mass, the deformation force gives a relative change in volume: + +$$ +p = -K \frac{dV}{\Delta V} +$$ (eq:hooke) + +where the pressure $p$ is introduced as being the force per unit area, $K$ is called the bulk modulus, and the minus sign expresses that the pressure is opposite to the deformation direction. Now we assume that the volume change is only in one direction (1-dimensional) as shown in {numref}`fig-cube`, so then we get: + +$$ +\begin{aligned} +\frac{dV}{\Delta V} & = + \frac{u_x(x+\Delta X)\Delta Y \Delta Z- u_x(x) \Delta Y \Delta Z} + {\Delta X \Delta Y \Delta Z} \\ +& = \frac{u_x(x+\Delta X) - u_x(x)}{\Delta X} +\end{aligned} +$$ + +where $u_x$ is the displacement in the $x$-direction. Using the situation that $\Delta X$ is rather small, we can approximate $u_x(x+\Delta X)$ by $u_x(x) + ( \partial u_x/\partial x ) \Delta X$; this then gives for Hooke's Law: + +$$ +p = -K \frac{\partial u_x}{\partial x}. +$$ + +Since we are finally interested in particle velocities rather than displacements (since geophones, seismic sensors on land, measure particle velocities), we differentiate both sides of Hooke's Law with respect to time $t$, and introduce $v_x = \partial u_x/\partial t$ to give: + +$$ +\boxed{ +\frac{1}{K} \frac{\partial p}{\partial t} = - \frac{\partial v_x}{\partial x} +} +$$ + +This is the so-called deformation equation. It is one basic relation needed for describing one-dimensional wave motion. + +The other relation is obtained via Newton's Law, applied to the volume $\Delta V$ with mass $M$ in the direction $x$, since we consider 1-dimensional motion: + +$$ +\begin{aligned} +F_x & = M \frac{\partial v_x}{\partial t} \\ + & = \rho \Delta V \frac{\partial v_x}{\partial t} +\end{aligned} +$$ (eq:newton) + +where $F$ is the total force that works on the element $\Delta V$ that induces motion. Consider the total force that is working on the cube in the $x$-direction, through the pressures working on the sides with area $\Delta Y \Delta Z$: + +$$ +\begin{aligned} +F_x & = - [ p(x+\Delta X) - p(x) ] \Delta S_x \\ + & = - \frac{p(x+\Delta X) - p(x)}{\Delta X} \Delta V +\end{aligned} +$$ + +Using $p(x+\Delta X) \simeq p(x) + ( \partial p/\partial x ) \Delta X$ and combining it with Newton's Law as expressed in {eq}`eq:newton` gives: + +$$ +\boxed{ + - \frac{\partial p}{\partial x} = \rho \frac{\partial v_x}{\partial t} +} +$$ + +since $\Delta V$ cancels. This equation is called the equation of motion. It is the other basic relation (next to the deformation equation) needed to describe one-dimensional wave motion. diff --git a/book/4_mechanical_waves/appendix_strain_p_s.md b/book/4_mechanical_waves/appendix_strain_p_s.md new file mode 100644 index 0000000..2fb8610 --- /dev/null +++ b/book/4_mechanical_waves/appendix_strain_p_s.md @@ -0,0 +1,375 @@ +(app-elastic)= +# Appendix: strain, P- and S-waves + +*In this appendix, strain for an elastic solid is explained. Together with the stress (discussed in the main text), it is used to derive the basic equations for P- and S-waves: the deformation equations and the equations of motion.* + +## Strain + +Strain is a geometrical quantity. It is a *relative* displacement under applied forces, i.e., it is a measure of deformation, normalized by its original size. As for stress, strain may be divided into normal strain and shear strain, depending on the type of force applied. For a normal strain in the deformation of a volume, the strain is simply the change of volume divided by its original volume, i.e.,: + +$$ +e_{\text{normal}} = \frac{\Delta V}{V} +$$ + +where $e$ is the strain, $\Delta V$ the change in volume and $V$ the original volume itself. This volume change was also used to derive the acoustic wave equation (see [the appendix on 1-D acoustic wave motion](./appendix_acoustic_1d.md)). + +Let us now look at {numref}`fig-ap-straindispl`, where the displacement $\underline{u}$ is given for a point $\underline{x}$. Notice that the displacement is a function of $\underline{x}$, i.e., $\underline{u} = \underline{u} (\underline{x})$. When a force/stress is applied, we get a difference in displacement, described by: + +$$ +\begin{aligned} +\underline{u} (\underline{x}+ d\underline{x}) & \simeq + \underline{u} (\underline{x}) + + \frac{\partial \underline{u}}{\partial \underline{x} } d\underline{x} \\ + & = \underline{u} (\underline{x}) + d\underline{u} +\end{aligned} +$$ + +where the first term is a translation and the second term is the term associated with deformation, in accordance with the assumption of elasticity. Notice that the term $\partial \underline{u}/ \partial \underline{x}$ is a matrix since both $\underline{u}$ and $\underline{x}$ are vectors: + +$$ + \frac{\partial \underline{u}}{\partial \underline{x} } = + \begin{pmatrix} + \frac{\partial u_x}{\partial x} & \frac{\partial u_x}{\partial y} & + \frac{\partial u_x}{\partial z} \\ + \frac{\partial u_y}{\partial x} & \frac{\partial u_y}{\partial y} & + \frac{\partial u_y}{\partial z} \\ + \frac{\partial u_z}{\partial x} & \frac{\partial u_z}{\partial y} & + \frac{\partial u_z}{\partial z} \\ + \end{pmatrix} +$$ + +The term $\partial \underline{u}/ \partial \underline{x}$ can be written in a symmetric and anti-symmetric part: + +$$ + \frac{\partial \underline{u}}{\partial \underline{x} } = + \underline{\underline{e}} - \frac{1}{2} \underline{\underline{\xi}} +$$ + +in which the elements of $\underline{\underline{e}}$ and $\underline{\underline{\xi}}$ are: + +$$ + e_{ij} = \frac{1}{2} + \left( \frac{\partial u_i}{\partial x_j} + \frac{\partial u_j}{\partial x_i} + \right) +$$ (eq:straindispl) + +$$ + \xi_{ij} = + \frac{\partial u_j}{\partial x_i} - \frac{\partial u_i}{\partial x_j} +$$ + +where $\underline{\underline{e}}$ is the so-called strain tensor, and $\underline{\underline{\xi}}$ represents rigid rotation. + +```{figure} figures/straindispl.PNG +:name: fig-ap-straindispl +:width: 60% + +Displacement field under presence of stress. +``` + +## Tensile stress and strain, and P-waves in a solid + +P-waves are associated with tensile stresses, so therefore, we consider the tensile stress and strain for an infinitesimal rectangular parallelepiped as shown in {numref}`fig-ap-ptens`. The sizes of the parallelepipeds are given by $\Delta X, \Delta Y$ and $\Delta Z$, while the changes therein are given by $\delta U_x, \delta U_y$ and $\delta U_z$. We apply a tensile stress in the $x$-direction only. As was also given in the appendix on acoustic wave motion, Hooke's law states that a force needed to extend or compress a spring is linearly related to the length ($u$) of extension/compression of that spring, so $F = k u.$ Stress is force per unit area, and strain is relative displacement, so Hooke's law applied to our parallelepiped gives: + +$$ +e_{xx} = \frac{\partial u_x}{\partial x} = \frac{\delta U_x}{\Delta X} = + \frac{1}{E} \tau_{xx} +$$ + +where $\tau_{xx}$ is the tensile stress and $e_{xx}$ the tensile strain in the $x$-direction, and $E$ is called Young's modulus. When applying a tensile stress, the size in the perpendicular directions $y$ and $z$ *decreases*, i.e., a lateral contraction occurs. This is quantified by the so-called Poisson's ratio, via: + +$$ +\begin{aligned} +e_{yy} & = \frac{\partial u_y}{\partial y} = \frac{\delta U_y}{\Delta Y} = + - \sigma e_{xx} \\ +e_{zz} & = \frac{\partial u_z}{\partial z} = \frac{\delta U_z}{\Delta Z} = + - \sigma e_{xx} +\end{aligned} +$$ + +We can follow the same procedure for a tensile stress in the $y$- and $z$-directions with tensile strains $e_{yy}$ and $e_{zz}$, giving totally: + +$$ + \begin{pmatrix} + e_{xx} \\ e_{yy} \\ e_{zz} + \end{pmatrix} + = \frac{1}{E} + \begin{pmatrix} + 1 & -\sigma & -\sigma \\ + -\sigma & 1 & -\sigma \\ + -\sigma & -\sigma & 1 + \end{pmatrix} + \begin{pmatrix} + \tau_{xx} \\ \tau_{yy} \\ \tau_{zz} + \end{pmatrix} +$$ (eq:etau) + +```{figure} figures/ptens.PNG +:name: fig-ap-ptens +:width: 60% + +Infinitesimal rectangular parallelepiped deformed by tensile stress. +``` + +So far, we have written down the basic expressions, but they are not in the desired form: we want to have a form in which the partial derivatives of the particle displacements are given (and not strains), and we want to have the stress on the left-hand side of the equation and the strains/particle-displacements on the right-hand side. To address the first issue, we have: + +$$ + \begin{pmatrix} + e_{xx} \\ e_{yy} \\ e_{zz} + \end{pmatrix} + = + \begin{pmatrix} + \frac{\partial u_x}{\partial x} \\ + \frac{\partial u_y}{\partial y} \\ + \frac{\partial u_z}{\partial z} + \end{pmatrix} +$$ + +To address the second issue, we have to invert the matrix in {eq}`eq:etau`. Since the inverted matrix has terms that are not very simple, the so-called Lamé parameters are introduced: + +$$ +\begin{aligned} + \lambda & = \frac{\sigma E}{ (1-2\sigma)(1+\sigma)} \\ + \mu & = \frac{E}{2 (1+\sigma)} +\end{aligned} +$$ + +where $\mu$ is known as the shear modulus. Using these, we then get: + +$$ + \begin{pmatrix} + \tau_{xx} \\ \tau_{yy} \\ \tau_{zz} + \end{pmatrix} + = + \begin{pmatrix} + \lambda + 2\mu & \lambda & \lambda \\ + \lambda & \lambda + 2\mu & \lambda \\ + \lambda & \lambda & \lambda + 2\mu + \end{pmatrix} + \begin{pmatrix} + \frac{\partial u_x}{\partial x} \\ + \frac{\partial u_y}{\partial y} \\ + \frac{\partial u_z}{\partial z} + \end{pmatrix} +$$ + +This is the desired expression that we will use next. + +Let us now derive the equations necessary to describe 1-D wave motion of a P-wave, travelling in the $x$-direction. To that end, consider {numref}`fig-ap-pblock`, in which again an infinitesimal block with size $\Delta X$, $\Delta Y$ and $\Delta Z$ is given. The mass $\Delta M$ of the little block is given by $\rho \Delta X \Delta Y \Delta Z$. We initiate a plane displacement field with displacements in the $x$-direction only (and therefore there is no contraction $\sigma$ for this 1-D case): + +$$ + \underline{u} (x,y,z,t) = + \begin{pmatrix} + u_x(x,t) \\ 0 \\ 0 + \end{pmatrix} +$$ + +In that case, Hooke's law gives $\tau_{xx} = (\lambda + 2\mu)\partial u_x/\partial x$. As for the acoustic case, we are finally interested in particle velocities rather than displacements (since geophones measure particle velocities), we differentiate both sides of Hooke's law with respect to time $t$, and introduce $v_x = \partial u_x/\partial t$ to give: + +$$ +\boxed{ + \frac{ \partial \tau_{xx} }{\partial t} = (\lambda + 2 \mu) + \frac{ \partial v_x }{\partial x} +} +$$ + +Note that this equation has the same shape as the equation for acoustic waves, i.e., + +$$ + - \frac{ \partial p }{\partial t} = K \frac{ \partial v_x }{\partial x} +$$ + +```{figure} figures/pblock.PNG +:name: fig-ap-pblock +:width: 60% + +Infinitesimal rectangular block under plane stress, used for deriving basic equations for P-wave motion. +``` + +This equation alone does not describe wave motion; to that end we need to apply Newton's law as well. Referring to {numref}`fig-ap-pblock`, the force is, in terms of stress: + +$$ + F_x = \Delta Y \Delta Z [ \tau_{xx}(x+\Delta X) - \tau_{xx}(x) ] +$$ + +and the force is given as mass times acceleration, i.e.: + +$$ + F_x = \Delta M \frac{\partial^2 u_x}{\partial t^2}. +$$ + +Equalizing these forces gives: + +$$ + \frac{ \tau_{xx}(x+\Delta X) - \tau_{xx}(x) }{\Delta X} + = + \frac{\Delta M}{\Delta X \Delta Y \Delta Z} + \frac{\partial^2 u_x}{\partial t^2} +$$ + +or, since $\tau_{xx}(x+\Delta X) \simeq \tau_{xx}(x) + ( \partial \tau_{xx}/\partial x ) \Delta X$: + +$$ + \frac{ \partial \tau_{xx} }{\partial x} + = + \rho \frac{\partial^2 u_x}{\partial t^2}. +$$ + +Again, we need to introduce the particle velocity for the displacement, giving: + +$$ +\boxed{ + \frac{ \partial \tau_{xx} }{\partial x} = + \rho \frac{\partial v_x}{\partial t}. +} +$$ + +This is the other desired equation, the equation of motion for P-waves. As expected, this equation has the same shape as the one for acoustic waves: + +$$ + - \frac{ \partial p }{\partial x} + = + \rho \frac{\partial v_x}{\partial t}. +$$ + +## Shear stress and strain, and S-waves in a solid + +S-waves are associated with shear stresses. We will follow the same line of derivation as for the P-waves but then with shear stresses: consider the shear stress and strain for an infinitesimal rectangle, deformed into a parallelogram (2D) as shown in {numref}`fig-ap-stens`, with sizes $\Delta X$ and $\Delta Z$. Let us first consider the left-hand figure (a), with $\tau_{xz}$. The shear modulus $\mu$ is defined as the constant that relates the stress and displacement, in this case as: + +$$ + \tau_{xz} = \mu \frac{\delta U_x}{\Delta Z} +$$ + +which is the shear equivalent of Hooke's law for elastic deformation. Since the associated strain $e_{xz}$ was defined as $(1/2) ( \partial u_z/\partial x + \partial u_x/\partial z)$ (see {eq}`eq:straindispl`), which for the parallelogram becomes: + +$$ + e_{xz} = \frac{1}{2} \frac{\delta U_x}{\Delta Z}, +$$ + +the stress-strain relationship for shear deformation becomes: + +$$ + \tau_{xz} = 2 \mu e_{xz}. +$$ + +```{figure} figures/stens.PNG +:name: fig-ap-stens +:width: 70% + +Infinitesimal rectangle deformed to parallelogram by shear stress. +``` + +This was the analysis for shear deformation in the horizontal direction, but deformation can also take place in the vertical direction, as shown in {numref}`fig-ap-stens`(b). In that case we have for the stress and strain: + +$$ +\begin{aligned} + \tau_{zx} & = \mu \frac{\delta U_z}{\Delta X} \\ + e_{zx} & = \frac{1}{2} \frac{\delta U_z}{\Delta X} \\ + \tau_{zx} & = 2 \mu e_{zx}. +\end{aligned} +$$ + +The deformations as shown in {numref}`fig-ap-stens`(a) and (b) are actually deformations with a rigid-body rotation where $e_{xz} \neq e_{zx}$. We are interested in the deformation which show no rigid-body rotation, as shown in {numref}`fig-ap-stens`(c). For no rigid-body rotation $\xi_{xz}=0$, so: + +$$ + \frac{\partial u_x}{\partial z} = \frac{\partial u_z}{\partial x}, + \qquad \text{or} \qquad + \frac{\delta U_x}{\Delta Z} = \frac{\delta U_z}{\Delta X}, +$$ + +We then have: + +$$ + e_{xz} = e_{zx}, +$$ + +and therefore: + +$$ + \tau_{xz} = \tau_{zx}. +$$ + +Similarly, for no rigid-body rotation in 3-D: + +$$ +\begin{aligned} + e_{xy} & = e_{yx} \\ + e_{yz} & = e_{zy} \\ + \tau_{xy} & = \tau_{yx} \\ + \tau_{yz} & = \tau_{zy} +\end{aligned} +$$ + +Let us now derive the equations necessary to describe 1-D wave motion of an S-wave, travelling in the $x$-direction (as for the P-wave). To that end, consider {numref}`fig-ap-sblock` in which again an infinitesimal block with size $\Delta X$, $\Delta Y$ and $\Delta Z$ and mass $\Delta M = \rho \Delta X \Delta Y \Delta Z$ is given. We initiate a plane displacement field, giving displacements in the $z$-direction only (for P-waves they were in the $x$-direction only): + +$$ + \underline{u} (x,y,z,t) = + \begin{pmatrix} + 0 \\ 0 \\ u_z(x,t) + \end{pmatrix} +$$ + +This means that there are no tensile stresses (since $u_z = u_z(x,t)$ only), and the other shear stresses $\tau_{xy}$ and $\tau_{yz}$ are zero. The shear equivalent of Hooke's law gives: + +$$ + \tau_{zx} = 2\mu e_{zx} = 2\mu \cdot \frac{1}{2} \left( + \frac{\partial u_z}{\partial x} + \frac{\partial u_x}{\partial z} \right) + = \mu \frac{\partial u_z}{\partial x} +$$ + +As for P-waves, in order to introduce the particle velocity $v_z$, we differentiate both sides with respect to time $t$ and take the particle velocity as $v_z = \partial u_z/\partial t$ to give: + +$$ +\boxed{ + \frac{\partial \tau_{zx}}{\partial t} = \mu \frac{\partial v_z}{\partial x}. +} +$$ + +This is the desired expression for the deformation. + +```{figure} figures/sblock.PNG +:name: fig-ap-sblock +:width: 60% + +Infinitesimal rectangular block under plane stress, used for deriving basic equations for S-wave motion. +``` + +As before, this equation alone does not describe wave motion since we need to apply Newton's law as well. Referring to {numref}`fig-ap-sblock`, the force is, in terms of stress: + +$$ + F_z = \Delta Y \Delta Z [ \tau_{zx}(x+\Delta X) - \tau_{zx}(x) ] +$$ + +and the force is given as mass times acceleration, i.e.: + +$$ + F_z = \Delta M \frac{\partial^2 u_z}{\partial t^2}. +$$ + +Equalizing these forces gives: + +$$ + \frac{ \tau_{zx}(x+\Delta X) - \tau_{zx}(x) }{\Delta X} + = + \frac{\Delta M}{\Delta X \Delta Y \Delta Z} + \frac{\partial^2 u_z}{\partial t^2} +$$ + +or, since $\tau_{zx}(x+\Delta X) \simeq \tau_{zx}(x) + ( \partial \tau_{zx}/\partial x ) \Delta X$: + +$$ + \frac{ \partial \tau_{zx} }{\partial x} + = + \rho \frac{\partial^2 u_z}{\partial t^2}. +$$ + +Again, we need to introduce the particle velocity via the displacement, giving: + +$$ +\boxed{ + \frac{ \partial \tau_{zx} }{\partial x} = + \rho \frac{\partial v_z}{\partial t}. +} +$$ + +This is the other desired equation, the equation of motion for S-waves. diff --git a/book/4_mechanical_waves/basic_notions.md b/book/4_mechanical_waves/basic_notions.md new file mode 100644 index 0000000..6f92f15 --- /dev/null +++ b/book/4_mechanical_waves/basic_notions.md @@ -0,0 +1,53 @@ +# Basic physical notion of waves + +The seismic method makes use of the properties of the velocity of seismic waves. This velocity is different for different rocks and it is this difference which is exploited in the seismic method. When we create a wave field at or near the surface of the earth, some energy will be reflected back (bounced back). They can be viewed as echoes. From these echoes we can determine the velocities of the rocks, as well as the depths where the echoes came from. In this chapter we will discuss the basic principles behind the behaviour of seismic wave fields in solid materials. When we use the seismic method, we usually discuss two types of seismic methods, depending on whether the distance from the sound source to the detector (the "ear") is large or small with respect to the depth of interest: the first is known as refraction seismics, the other as reflection seismics. Of course, there are overlaps and differences between those two types which will be discussed in this chapter. + +Everybody knows what waves are when we are talking about waves at sea. Seismic wave fields in materials have the same kind of behaviour as these waves, only they travel much faster than the waves we see at sea. Waves can occur in several ways. We will consider two types of them, namely the longitudinal and the shear wave. Longitudinal waves behave like waves in a large spring. When we push from one side of a spring, we will observe a wave going through the spring which characterizes itself by a thickening of the wires running through the spring in time (see also {numref}`fig-pands`). A property of this type of wave is that the motion of a piece of the wire is in the same direction as the wave moves. These waves are also called Push-waves, abbreviated to P-waves, or compressional waves. Another type of wave is the shear wave. A shear wave can be compared with a chord. When we push a chord upward from one side, a wave will run along the chord to the other side. The movement of the chord itself is only up- and downward: characteristic of this wave is that a piece of the chord is moving perpendicular to the direction of that of the wave (see also {numref}`fig-pands`). These types of waves are referred to as S-waves, also called shear waves. Characteristic of this wave is that a piece of the chord is pulling its "neighbour" upward, and this can only occur when the material can support shear stress. In fluids, one can imagine that a "neighbour" cannot be pulled upward simply because it is a fluid. Therefore, in fluids only P-waves exist, while in a solid both P- and S-waves exist. + +```{figure} figures/blokjes.png +:name: fig-pands +:width: 80% + +Particle motion of P and S waves, where the particle motion for SV is in the vertical direction only and for SH in the horizontal direction only. +``` + +In the real world, we deal with three spatial dimensions, so a wave will spread in three directions. In a homogeneous medium (so the properties of the material are everywhere constant and the same), the wave will spread out like a sphere. The outer shell of this sphere is called the wave front. Another way of describing this wave front is in terms of the normal to the wavefront: the ray. We are used to rays in optics and we can use the same notion in the seismic method. When we were explaining the behaviour of P- and S-waves, we already used the term "neighbour". This was an important feature; otherwise the wave would not move forward. A fundamental notion included in this, is Huygens' principle. When a wave front arrives at a certain point, that point will behave also as a source for the wave, and so will all its neighbours. The new wavefront is then the envelope of all the waves that were generated by these points. This is illustrated in {numref}`fig-huygens`. Again, the ray can then be defined as the normal to that envelope which is also given in the figure. + +```{figure} figures/huygens.png +:name: fig-huygens +:width: 80% + +Using Huygens' principle to locate new wavefronts. +``` + +So far, we only discussed the way in which the wave moves forward, but there is also another property of the wave we have not discussed yet, namely the amplitude: how does the amplitude behave as the wave moves forward? We have already mentioned spherical spreading when the material is everywhere the same. The total energy will be spread over the area over the sphere. This type of energy loss is called spherical divergence. It simply means that if we put our "ear" at a larger distance, the sound will be less loud. There is also another type of energy loss, that is due to losses within the material, which mainly consists of internal friction losses. This means that the amplitude of a wave will be extra damped because of this property. S-waves usually show higher friction losses than P-waves. Finally, we give a table of common rocks and their seismic wave velocities in {numref}`tab-wavevel`. + +```{list-table} Seismic wave velocities for some common media, soils and rocks. +:name: tab-wavevel +:header-rows: 1 + +* - Material + - Wave velocity (m/s) + - Material + - Wave velocity (m/s) +* - Air + - 330 + - Sandstone + - 2000-4500 +* - Water + - 1500 + - Shales + - 3900-5500 +* - Soil + - 20-300 + - Limestone + - 3400-7000 +* - Sands + - 600-1850 + - Granite + - 4800-6000 +* - Clays + - 1100-2500 + - Ultra-mafic rocks + - 7500-8500 +``` diff --git a/book/4_mechanical_waves/data/shot_group_0.npz b/book/4_mechanical_waves/data/shot_group_0.npz new file mode 100644 index 0000000..9cb9a49 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_0.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_1.npz b/book/4_mechanical_waves/data/shot_group_1.npz new file mode 100644 index 0000000..710b7da Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_1.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_10.npz b/book/4_mechanical_waves/data/shot_group_10.npz new file mode 100644 index 0000000..43711c9 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_10.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_11.npz b/book/4_mechanical_waves/data/shot_group_11.npz new file mode 100644 index 0000000..0ef2489 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_11.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_12.npz b/book/4_mechanical_waves/data/shot_group_12.npz new file mode 100644 index 0000000..086c0fb Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_12.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_13.npz b/book/4_mechanical_waves/data/shot_group_13.npz new file mode 100644 index 0000000..ce23250 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_13.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_14.npz b/book/4_mechanical_waves/data/shot_group_14.npz new file mode 100644 index 0000000..69248b9 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_14.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_15.npz b/book/4_mechanical_waves/data/shot_group_15.npz new file mode 100644 index 0000000..c4331de Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_15.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_2.npz b/book/4_mechanical_waves/data/shot_group_2.npz new file mode 100644 index 0000000..29c66a3 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_2.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_3.npz b/book/4_mechanical_waves/data/shot_group_3.npz new file mode 100644 index 0000000..27d0fb7 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_3.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_4.npz b/book/4_mechanical_waves/data/shot_group_4.npz new file mode 100644 index 0000000..0fe9ead Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_4.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_5.npz b/book/4_mechanical_waves/data/shot_group_5.npz new file mode 100644 index 0000000..89549e9 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_5.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_6.npz b/book/4_mechanical_waves/data/shot_group_6.npz new file mode 100644 index 0000000..2eedbfe Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_6.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_7.npz b/book/4_mechanical_waves/data/shot_group_7.npz new file mode 100644 index 0000000..e4c046a Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_7.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_8.npz b/book/4_mechanical_waves/data/shot_group_8.npz new file mode 100644 index 0000000..f41fb7a Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_8.npz differ diff --git a/book/4_mechanical_waves/data/shot_group_9.npz b/book/4_mechanical_waves/data/shot_group_9.npz new file mode 100644 index 0000000..2e2dab2 Binary files /dev/null and b/book/4_mechanical_waves/data/shot_group_9.npz differ diff --git a/book/4_mechanical_waves/elastic_waves.md b/book/4_mechanical_waves/elastic_waves.md new file mode 100644 index 0000000..51b03e7 --- /dev/null +++ b/book/4_mechanical_waves/elastic_waves.md @@ -0,0 +1,108 @@ +# Wave fields in a solid: elastic (P and S) waves + +## Stress + +Here we define *stress*. Stress can be defined as the force per unit area exerted on a body across an imaginary surface (see also {numref}`fig-stressforce`). Since the dimension of stress is of a pressure, i.e., force per unit area, the quantities of stress are also given in the dimension of pressure, i.e., Pa. Therefore, the stress can be seen as the equivalent of pressure in an (elastic) solid. One can discern normal stress as the stress perpendicular to a surface, and shear stress as the one parallel to a surface. The normal stress is also called compressional or tensile stress. Since a stress can be in any direction to a surface, the stress can be decomposed into components perpendicular and parallel to the surface. This decomposition matrix is also called the stress tensor. In formula form, this can all be written as: + +$$ + \frac{\underline{F}}{\Delta S} = + \underline{\underline{\tau}} \, \underline{n} +$$ + +where $F$ is the force, $\Delta S$ is the surface, $\underline{\underline{\tau}}$ is the stress tensor and $\underline{n}$ is the vector normal to the surface $\Delta S$. When writing out the matrix of the stress, i.e., the stress tensor, in terms of the coordinates $x$, $y$ and $z$, we get: + +$$ + \underline{\underline{\tau}} = + \begin{pmatrix} + \tau_{xx} & \tau_{xy} & \tau_{xz} \\ + \tau_{yx} & \tau_{yy} & \tau_{yz} \\ + \tau_{zx} & \tau_{zy} & \tau_{zz} + \end{pmatrix} +$$ + +Some of these factors are visualized in {numref}`fig-tautensor`. + +```{figure} figures/stressforce.PNG +:name: fig-stressforce +:width: 60% + +Definition of stress for a force working on a surface $\Delta S$. +``` + +In order to see the equivalence with the acoustic case, consider the case where no shear stresses exist. Then the diagonal elements of the matrix are the only non-zero ones, and the stress matrix can be written as: + +$$ + \underline{\underline{\tau}}_{\text{no-shear}} = + \begin{pmatrix} + -p & 0 & 0 \\ + 0 & -p & 0 \\ + 0 & 0 & -p + \end{pmatrix} +$$ + +where $p$ is the pressure. Notice that there is a minus sign since commonly the positive sign for pressure is for a compressional force, while for stress it is for a tensile force. + +```{figure} figures/tautensor.PNG +:name: fig-tautensor +:width: 60% + +Definition of stress components for stresses working on an infinitesimal parallelepiped. +``` + +## P-waves in an elastic solid + +For 1-D wave motion in the $x$-direction, Hooke's law gives for the plane tensile stress $\tau_{xx}$ (see [the appendix on strain, P- and S-waves](./appendix_strain_p_s.md)): + +$$ + \frac{\partial \tau_{xx}}{\partial t} = (\lambda + 2\mu) + \frac{\partial v_x}{\partial x} +$$ + +where $\lambda$ and $\mu$ are the so-called Lamé parameters. $\lambda$ is the first Lamé parameter, and $\mu$ is the shear modulus; in 3-D, $\lambda$ is related to the bulk modulus $K$ through $K = \lambda + (2/3)\mu$. This equation is called the deformation equation for a P-wave in an elastic solid. Note that this equation has the same form as the deformation equation for acoustic waves (see {eq}`eq:eqdeform`). + +Then applying Newton's law gives an equation nearly equivalent to the one for the acoustic case, but now having tensile stress instead of pressure (see also [the appendix on strain, P- and S-waves](./appendix_strain_p_s.md)): + +$$ +\frac{\partial \tau_{xx}}{\partial x} = \rho \frac{\partial v_x}{\partial t} +$$ + +This is the equation of motion for a P-wave. Combining the deformation equation and the equation of motion gives, as for the acoustic case, the wave equation for the stress, assuming the density being constant: + +$$ +\frac{\partial^2 \tau_{xx}}{\partial x^2} + - \frac{1}{c^2_P} \frac{\partial^2 \tau_{xx}}{\partial t^2} = 0 +$$ + +where $c^2_P = (\lambda + 2\mu)/\rho$ is the squared P-wave velocity. This wave equation describes the wave propagation for P-waves in an elastic solid. + +## S-waves in an elastic solid + +Let us now consider shear stresses which, as we shall see, will result in a wave equation for S-waves. To that end, we consider 1-D displacement in the $z$-direction for a wave propagating in the $x$-direction for the 1-D shear motion. The equivalent of Hooke's law for shear stress results in (see [the appendix on strain, P- and S-waves](./appendix_strain_p_s.md)): + +$$ + \frac{\partial \tau_{zx}}{\partial t} = \mu \frac{\partial v_z}{\partial x} +$$ (eq:deformS) + +where $\tau_{zx}$ is the shear stress. This is the deformation equation for an S-wave. + +Then applying Newton's law for a shear stress gives (see also [the appendix on strain, P- and S-waves](./appendix_strain_p_s.md)): + +$$ + \frac{\partial \tau_{zx}}{\partial x} = \rho \frac{\partial v_z}{\partial t} +$$ (eq:eqmotionS) + +which is the equation of motion for S-waves. Combining the deformation equation and the equation of motion gives the wave equation for the shear stress, assuming the density being constant: + +$$ +\frac{\partial^2 \tau_{zx}}{\partial x^2} + - \frac{1}{c^2_S} \frac{\partial^2 \tau_{zx}}{\partial t^2} = 0 +$$ (eq:waveqStau) + +where $c^2_S = \mu / \rho$ is the squared S-wave velocity. This wave equation describes the wave propagation for S-waves in an elastic solid. + +With respect to the (1-D) reflection coefficients for P- and S-waves at the boundary of two elastic solids: the derivations go similar as for the acoustic case, as worked out in the previous section: + +- For P-waves, we require the continuity of the tensile stress $\tau_{xx}$ and the particle velocity $v_x$ at the interface, and +- For S-waves we require the continuity of the shear stress $\tau_{zx}$ and the particle velocity $v_z$ at the interface. + +The resulting expressions for the reflection and transmission coefficient are the same as for the acoustic case, only now the velocities are for the elastic solid. (See the [*EXERCISES*](./exercises.md)) diff --git a/book/4_mechanical_waves/exercise_4a.md b/book/4_mechanical_waves/exercise_4a.md new file mode 100644 index 0000000..d41c07a --- /dev/null +++ b/book/4_mechanical_waves/exercise_4a.md @@ -0,0 +1,185 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +mystnb: + # The cells are to be filled in and run by the reader, so the page must not be + # executed at build time. + execution_mode: 'off' +--- + +# Exercise 4a: Model traveltimes for seismic wavefield from one shot + +In this exercise you will model the traveltimes of a seismic wavefield for a direct, refracted and reflected wave. The model contains only one boundary, giving rise to a reflection and a head wave (a critically refracted wave) when the wave speed of the second medium is higher than the wave speed of the first medium. + +To this aim, we will use a synthetically generated wave field for one shot position. Sixteen (0-15) wave-field recordings are present: + +- Take the first character of your first name, take the number of this character in the alphabet and if it is larger than 15, subtract 15. +- Make this your group number as a string variable. + +```{code-cell} ipython3 +your_group_no = "" +``` + +```{code-cell} ipython3 +# Housekeeping, no physics. Running this page in the browser, the next lines fetch +# your own shot gather from the book. Running the notebook on your own machine, with +# the .npz file already beside it, they do nothing. +import os +import pathlib + +filename_npz = "shot_group_" + your_group_no + ".npz" + +if not pathlib.Path(filename_npz).exists(): + from pyodide.http import pyfetch + # Live Code runs Python in a worker, which would resolve a plain "data/..." + # against itself and not against this page. The working directory mirrors the + # folder this page sits in on the server, so it gives the address to ask for. + url = os.getcwd().split("/home/pyodide/book")[-1] + "/data/" + filename_npz + response = await pyfetch(url) + if response.status != 200: + raise FileNotFoundError( + url + " -> HTTP " + str(response.status) + + ". Is your_group_no a number from 0 to 15?") + pathlib.Path(filename_npz).write_bytes(await response.bytes()) + print("fetched", filename_npz) + +# The hover read-out on the figures needs ipympl, which the browser lacks. +try: + import ipympl # noqa: F401 +except ModuleNotFoundError: + import micropip # browser only; locally, pip install ipympl + await micropip.install("ipympl") + +# Cosmetic only. ipympl stacks its toolbar vertically, which this theme stretches +# across the page, and it names two of its icons in Font Awesome 4 while the book +# ships Font Awesome 6. +try: + from ipympl.backend_nbagg import Canvas + from IPython.display import display, HTML + Canvas.toolbar_position.default_value = "top" + display(HTML(r"")) +except Exception: + pass # the figures work regardless of how it looks +``` + +Now you will read this wavefield data set, that includes the geometry of the data, so the positions of the source and receivers. To that end: + +- Run the next code, and consider/analyze the source and receiver configuration. +- Where is the source positioned compared to the receiver positions (beginning, end, or somewhere else)? + +```{code-cell} ipython3 +#%matplotlib qt +%matplotlib ipympl + +import matplotlib.pyplot as plt +import numpy as np + +# Reading NPZ file +filename_npz = "shot_group_" + your_group_no + ".npz" + +with open(filename_npz, "rb") as f: + npzfile = np.load(f) ; print(npzfile.files) + Data = npzfile['Data'] + timevector = npzfile['tt'] + x_receivers = npzfile['x_receivers'] + x_source = npzfile['x_source'] + +# Check: +#print(Data[1,1]) +#print(timevector[1]) +#print(x_receivers[1]) +#print(x_source) + +plt.close("geometry") # so a re-run redraws instead of stacking +plt.figure( "geometry", figsize = ( 12, 6 ), dpi = 60 ) # fits the canvas to the page +plt.plot(x_receivers,'o',color='b') +plt.plot(x_source,'x',color='r', markersize=10) +plt.legend(['x_receivers','x_source']) +plt.xlabel('index'); plt.ylabel('Distance (m)') +plt.title(' Distance of source and receivers versus index of array', fontsize=14 ) +plt.show() +``` + +Next, you need to generate the travel-time curves for that geometry. But, of course, you need to specify the parameters of the model, i.e., the velocities of the different waves and the depth of the boundary. The depth of the boundary may be different for the refractor and the reflector, but initially you can keep those depths the same. So to that end, using the variable names as set in the next code: + +- Specify the P-wave velocities of the first and second medium, and the surface-wave velocity (of the first medium) +- Specify the depths of the refractor and reflector (initially, take them the same) +- Play with the velocities and depths such that you can see the different events in the travel-time curves, in particular that you can see both a reflection and a head wave (critically refracted wave) + +```{code-cell} ipython3 +# Specify velocities and depths +c_directP = +c_directSurf = +c_refract = +depth_refract = +depth_reflect = +``` + +```{code-cell} ipython3 +tt_directP = np.zeros_like(x_receivers) +tt_directSurf = np.zeros_like(x_receivers) +tt_refract = np.zeros_like(x_receivers) +tt_reflect = np.zeros_like(x_receivers) + +# direct P-wave: +tt_directP[:] = abs(x_receivers[:]-x_source)/c_directP ; print('tt_directP = ',tt_directP[0:3]) + +# direct Surface wave: +tt_directSurf[:] = abs(x_receivers[:]-x_source)/c_directSurf ; print('tt_directSurf = ',tt_directSurf[0:3]) + +# refracted P-wave: +sin_crit = c_directP/c_refract +cos_crit = np.sqrt(1-sin_crit*sin_crit) +tt_refract[:] = abs(x_receivers[:]-x_source)/c_refract + 2.0*depth_refract*cos_crit/c_directP ; print('tt_refract = ',tt_refract[0:3]) + +# find limiting indices of array when distance < x_crit (then no critical refraction): +x_crit = 2.0 * depth_refract * sin_crit/cos_crit ; print('x_crit = ',x_crit,' m') +# left end: +i1 = 0 +ii_end = len(x_receivers) #; print('iiend = ',ii_end) +for ii in range (0,len(x_receivers)): + if abs(x_receivers[ii]-x_source) < x_crit: + break + else: + i1 = ii +#print('i1 =',i1,'; x_receivers[i1] = ',x_receivers[i1]) +#print('abs(x_receivers[i1]-x_source) = ',abs(x_receivers[i1]-x_source)) + +# right end: +i2 = len(x_receivers) +for ii in range (ii_end-1,0,-1): + if abs(x_receivers[ii]-x_source) < x_crit: + break + else: + i2 = ii +#print('i2 =',i2,'; x_receivers[i2] = ',x_receivers[i2]) +#print('abs(x_receivers[i2]-x_source) = ',abs(x_receivers[i2]-x_source)) + + +# reflected P-wave: +t0 = 2*depth_reflect/c_directP +tt_reflect[:] = np.sqrt(t0*t0 + (x_receivers[:]-x_source)*(x_receivers[:]-x_source)/(c_directP*c_directP)) +print('tt_reflect = ',tt_reflect[0:3]) + +plt.close("traveltimes") # so a re-run redraws instead of stacking +plt.figure( "traveltimes", figsize = ( 16, 12 ), dpi = 45 ) # fits the canvas to the page +plt.plot(x_receivers, tt_directP, 'x',color='b') +plt.plot(x_receivers, tt_directSurf, 'x',color='c') +plt.plot(x_receivers[0:i1], tt_refract[0:i1], 'x',color='g') +plt.plot(x_receivers[i2:-1], tt_refract[i2:-1], 'x',color='g') +plt.plot(x_receivers, tt_reflect, 'x',color='r') +plt.axis( [np.min(x_receivers), np.max(x_receivers), np.min(timevector), np.max(timevector)] ) +plt.gca().invert_yaxis() +plt.legend(['directP','directSurf','refraction','','reflection']) +plt.show() +``` diff --git a/book/4_mechanical_waves/exercise_4b.md b/book/4_mechanical_waves/exercise_4b.md new file mode 100644 index 0000000..fbfc919 --- /dev/null +++ b/book/4_mechanical_waves/exercise_4b.md @@ -0,0 +1,193 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +mystnb: + # The cells are to be filled in and run by the reader, so the page must not be + # executed at build time. + execution_mode: 'off' +--- + +# Exercise 4b: Interpret velocities and depths from seismic wavefield from one shot + +In this exercise you will interpret direct, refracted and reflected waves from a (synthetically generated) seismic wavefield recording. And will check the results via forward modelling, as you did in [Exercise 4a](./exercise_4a.md). + +To this aim, use the same synthetically generated wave field that you used before: + +- Take the first character of your first name, take the number of this character in the alphabet and if it is larger than 15, subtract 15. +- Make this your group number as a string variable. + +```{code-cell} ipython3 +your_group_no = "" +``` + +```{code-cell} ipython3 +# Housekeeping, no physics. Running this page in the browser, the next lines fetch +# your own shot gather from the book. Running the notebook on your own machine, with +# the .npz file already beside it, they do nothing. +import os +import pathlib + +filename_npz = "shot_group_" + your_group_no + ".npz" + +if not pathlib.Path(filename_npz).exists(): + from pyodide.http import pyfetch + # Live Code runs Python in a worker, which would resolve a plain "data/..." + # against itself and not against this page. The working directory mirrors the + # folder this page sits in on the server, so it gives the address to ask for. + url = os.getcwd().split("/home/pyodide/book")[-1] + "/data/" + filename_npz + response = await pyfetch(url) + if response.status != 200: + raise FileNotFoundError( + url + " -> HTTP " + str(response.status) + + ". Is your_group_no a number from 0 to 15?") + pathlib.Path(filename_npz).write_bytes(await response.bytes()) + print("fetched", filename_npz) + +# The hover read-out on the figures needs ipympl, which the browser lacks. +try: + import ipympl # noqa: F401 +except ModuleNotFoundError: + import micropip # browser only; locally, pip install ipympl + await micropip.install("ipympl") + +# Cosmetic only. ipympl stacks its toolbar vertically, which this theme stretches +# across the page, and it names two of its icons in Font Awesome 4 while the book +# ships Font Awesome 6. +try: + from ipympl.backend_nbagg import Canvas + from IPython.display import display, HTML + Canvas.toolbar_position.default_value = "top" + display(HTML(r"")) +except Exception: + pass # the figures work regardless of how it looks +``` + +Now you will read this wavefield data set, that includes the geometry of the data and data themselves. To that end: + +- Run the next code, consider/analyze the source and receiver configuration again, and consider/analyze the wavefield data. +- In the code, the maximum amplitude (`maxAmplitude`) is set; adapt this maximum amplitude and look at the effect on the plot. + +```{code-cell} ipython3 +#%matplotlib qt +%matplotlib ipympl + +import matplotlib.pyplot as plt +import numpy as np + +# Reading NPZ file +filename = "shot_group_" + your_group_no +filename_npz = filename + ".npz" + +with open(filename_npz, "rb") as f: + npzfile = np.load(f) ; print(npzfile.files) + Data = npzfile['Data'] + timevector = npzfile['tt'] + x_receivers = npzfile['x_receivers'] + x_source = npzfile['x_source'] + +# Check: +#print(Data[1,1]) +#print(timevector[1]) +#print(x_receivers[1]) +#print(x_source) + +# Plot geometry of shot gather +plt.close("geometry") # so a re-run redraws instead of stacking +plt.figure( "geometry", figsize = ( 12, 6 ), dpi = 60 ) # fits the canvas to the page +plt.plot(x_receivers,'o',color='b') +plt.plot(x_source,'x',color='r', markersize=10) +plt.legend(['x_receivers','x_source']) +plt.xlabel('index'); plt.ylabel('Distance (m)') +plt.title(' Distance of source and receivers versus index of array', fontsize=14 ) +plt.show() +``` + +```{code-cell} ipython3 +# Plot extracted shot gather +plt.close("shot gather") # so a re-run redraws instead of stacking +plt.figure( "shot gather", figsize = ( 16, 12 ), dpi = 45 ) # fits the canvas to the page +maxAmplitude = 0.04 * np.max( np.abs(Data) ) +extent = [ np.min(x_receivers), np.max(x_receivers), np.max(timevector), np.min(timevector) ] +# Standard colormap: +# plt.imshow( Data, vmin=-maxAmplitude, vmax = maxAmplitude, extent = extent, aspect = 'auto' ) +plt.imshow( Data, vmin=-maxAmplitude, vmax = maxAmplitude, extent = extent, aspect = 'auto', cmap='seismic' ) +titleplot = filename + " : original" +plt.title(titleplot, fontsize=14 ) +plt.colorbar() +plt.show() +``` + +## Identification of events + +The figure of the wavefield data is a simulation of a seismic wavefield recording. On this wavefield recording, determine which event(s) can be interpreted as: + +- Direct P-wave +- (Critically) refracted P-wave +- Direct surface wave +- P-wave reflections + +You may have to play with `maxAmplitude` to see some events better. + +## Estimation of wave velocity of events + +Based on this identification, determine the velocity of the: + +- Direct P-wave +- Head wave (Critically refracted P-wave) +- Direct surface wave + +In order to estimate the velocity of a reflected wave, first consider the equation for a reflection-hyperbola, i.e., + +$$ +T^2 = T_0^2 + \frac{X^2}{c^2}, +$$ + +where $T_0$ is the time at the apex of the hyperbola, and $X$ is the horizontal distance from the apex, so the relative horizontal distance between the source and receiver. From this equation, the velocity can be made explicit: + +$$ +c = \frac{X}{\left( T^2 - T_0^2 \right)^{1/2}}. +$$ + +Based on this: + +- Estimate the velocity from one of the reflections you picked above. + +## Estimation of depth of refractor and reflector + +Based on the above, depth estimates can be made. Let us first estimate the depth of the **refractor**, using the cross-over distance, the distance where the direct wave and the head-wave (critically refracted) cross each other. This is given by: + +$$ +Z_{\mathrm{refractor}} = \frac{X_{\mathrm{cross}}}{2} + \left[ \frac{c_2-c_1}{c_2+c_1} \right]^{1/2}, +$$ + +where $c_1$ is the velocity of the direct P-wave and $c_2$ the velocity of the (P-wave) refractor. + +Based on this: + +- Determine the depth of the refractor + +Let us now consider the **reflection** you took. At a distance $X=0$, the reflection time becomes $T_0 = 2z/c_{\mathrm{refl}}$. That reflection time can be picked from the wavefield recording, and the velocity you estimated earlier. Then the depth can be determined via $z = c_{\mathrm{refl}} T_0 /2$. + +Based on this: + +- Determine the depth of the reflector + +## Final check: forward model results via Exercise 4a + +Based on the above, you have now determined all the velocities and depths for which you can model the travel times as you did in [Exercise 4a](./exercise_4a.md). So therefore: + +- Run the travel-time code of Exercise 4a again, but now with the model parameters you estimated for your wavefield recording +- Check whether the travel times match the ones from your seismic wavefield recording above. + +This should give you confidence in your physical interpretation of the wavefield recording. diff --git a/book/4_mechanical_waves/exercises.md b/book/4_mechanical_waves/exercises.md new file mode 100644 index 0000000..e09167b --- /dev/null +++ b/book/4_mechanical_waves/exercises.md @@ -0,0 +1,29 @@ +# Exercises on fundamental physical laws, P- and S-waves + +1. From the deformation equation and the equation of motion for acoustic waves ({eq}`eq:eqdeform` and {eq}`eq:eqmotion`) show that the particle velocity $v_x$ also satisfies the wave equation, i.e., {eq}`eq:waveqacv`. + +2. Here we look at deriving the wave equation in a different way: + + - Show that from substituting the deformation equation {eq}`eq:eqdeform` and the equation of motion {eq}`eq:eqmotion` in the commutative property for the pressure, i.e., + + $$ + \frac{\partial}{\partial x} \left( \frac{\partial p}{\partial t} \right) + = + \frac{\partial}{\partial t} \left( \frac{\partial p}{\partial x} \right), + $$ + + the wave equation for the particle velocity is nicely obtained. + - In the same way show that from substituting the deformation equation {eq}`eq:eqdeform` and the equation of motion {eq}`eq:eqmotion` in the commutative property for the *particle velocity*, as expressed in {eq}`eq:commut`, the wave equation for the pressure is nicely obtained. + +3. From the deformation equation and the equation of motion for shear waves ({eq}`eq:deformS` and {eq}`eq:eqmotionS`) show that the particle velocity $v_z$ also satisfies the wave equation. + +4. Here we consider shear waves: + + - How can the solution of the wave equation for the shear stress ({eq}`eq:waveqStau`) be written? + - Based on this solution, *derive* the solution for the particle velocity $v_z$. + - What is the difference between the two? And how is that called? + +5. Here we consider shear waves arriving at an interface: + + - When we look at a reflection and transmission across an interface between two materials: we have an incident S-wave coming from above. How would you write the wave field (shear stress and particle velocity) above the interface? And how below? + - At the interface, we require the continuity of the shear stress and particle velocity, as given above: from this, *derive* the reflection and transmission coefficients. diff --git a/book/4_mechanical_waves/field_recordings.md b/book/4_mechanical_waves/field_recordings.md new file mode 100644 index 0000000..3175135 --- /dev/null +++ b/book/4_mechanical_waves/field_recordings.md @@ -0,0 +1,60 @@ +# Seismic wavefield recordings from the field: physical interpretation using kinematic concepts + +In this section, we will look at the physical interpretation of seismic wavefield data as recorded in the field, two recordings on land (one with rocky near-surface and one with loose-soil near-surface) and one recording at sea. + +## Seismic wavefield recording on land: rocky near-surface + +Let us first consider a seismic wave field recorded on land. In {numref}`fig-raw-shot-land` this wavefield record is shown. The first event we are considering is the "first arrival". It shows itself by giving a pulse after a quiet period. This arrival can be a *direct* arrival or a *refraction*, both of which we discussed earlier. When looking closely at the record, it can be seen that there is a slight change of dip, occurring at around an offset of 800 m. Therefore, the arrival until this distance is a direct arrival, while beyond that distance, it is the refraction. By drawing a straight line through the direct arrival, the velocity with which it propagates along the surface is: 2400 meters in 670 ms, so approximately 3600 m/s. This is a relatively high velocity, so there is probably some very hard rock at the surface. The velocity of the refracted arrival can also be determined by a straight line through that arrival; it amounts to 2400 meters in around 500 ms (note that the arrival does not go through the origin, so it is the difference between the time at $x=0$ m and at $x=2400$ m), so a velocity of 4800 m/s. Below the record in {numref}`fig-raw-shot-land`, a simple model is shown that explains this first arrival; the synthetic record belonging to this model is given on the top right of the figure. + +The next events we consider are the strong events that cross 2400 meter at some 1.3 seconds. This event is interpreted as ground-roll or surface waves (they propagate along the surface). Calculating the velocity, we come to 1850 m/s. Again, the simple model below the record explains this ground roll; the synthetic record on the top right of the figure also shows this arrival. + +```{figure} figures/Figure4_1.PNG +:name: fig-raw-shot-land +:width: 100% + +Field seismic wavefield recording from land survey (top left), synthetic seismogram (top right) using model of near surface (middle) and model at larger depths (bottom). +``` + +Also in this field record, a "high-frequency" event can be observed, which goes through the 4-second mark at about 1300 meters distance. Calculating the velocity from this, we come to some 325 m/s. It may be clear that this is a wave that goes through the air. This event is also synthesized in the top right figure, using the model as given below it. + +Last but not least, are "high-frequency" events which are slightly curved, e.g. the ones at 0.9 and 1.6 seconds. These events are interpreted as reflections from layer boundaries in the deep subsurface. Those are usually the events we are interested in when we want to obtain an image of the subsurface. Using a simple model as given at the bottom of the figure (which explains the deeper part of the earth), the synthetic record for these events is also shown in the top right of the figure. + +In the above, we have interpreted five types of events, which can be captured in one combined model and are shown in one combined synthetic seismogram. These synthetics explain the most important events in the raw seismic record. Still, when looking at the resulting synthetic seismogram, we see that we are very over-simplifying the situation, since the synthetic and field record are only resembling in the arrival times of the most important events. When looking at the general characteristics, they are very different indeed. + +## Seismic wavefield recording on land: loose-soil near-surface + +The field record we discussed so far was recorded on some hard rocks where the velocities are relatively high. However, when shooting data on land with loose top soil, in this case sand on a beach, the characteristics are much different. In {numref}`fig-raw-shot-wassenaar`, a field record of this situation is given. Again, we can determine the main events in this record. Let us first consider the "first arrival", i.e. the arrival that is coming in first after a quiet period. As usual, this is interpreted as a refraction, as shown in the figure below the record. The velocity can be determined: we come to some 1600 m/s. This velocity is very close to the velocity of water, so this refraction may be due to the water table. In the figure on the right, the synthetic shows this arrival. + +The next event is the most prominent one, namely the event that goes through the 1-second mark at some 180 m, so its velocity is around 180 m/s. This arrival is interpreted as "ground-roll"/surface waves, which travel along the surface. The model which explains this arrival is given again below the record, and its synthetic is shown on the top right. + +The most important events for this wavefield recording are the "high-frequency" events that are the slightly curved arrivals, which can all be interpreted as reflections from deep layers. The number of reflections are too many; only a few are synthesized in the record on the top right, using the model as given at the bottom of the figure. + +Again, when comparing the synthetic to the field seismogram, it is obvious that we have very over-simplified the earth; the positive side is that we have probably been able to understand most of the events in the field recording. + +```{figure} figures/Figure4_2.PNG +:name: fig-raw-shot-wassenaar +:width: 100% + +Field seismic wavefield recording from land survey with loose top soil (top left), synthetic seismogram (top right) using model of near surface (middle) and model at larger depths (bottom). +``` + +## Seismic wavefield recording at sea + +{numref}`fig-raw-shot-marine` shows a seismic wavefield recording, made at sea. This record is much "cleaner" than the land record, as we measure in a water layer, which is a very homogeneous layer. + +Let us analyze some separate events again. The first event in the marine record is the faint one, going nearly through the origin. It crosses the 500 meter at some 340 ms; this means a velocity of some 1470 m/s. It may be clear that this is the direct arrival from the source to the receivers through the water, as explained in the model below the record. This direct arrival is thus a body wave, since it travels with the velocity of water. + +The next event is the first arrival at farther offsets; this arrival is interpreted as a refractive event. When analyzing the distance travelled over time, i.e. the apparent velocity, a velocity of roughly 2000 m/s is obtained. Using the equation for a refraction ({eq}`eq:trefract`), a depth of 300 meter is obtained. This is quantified in the model below the figure, and its associated synthetic seismogram in the figure on the top right. + +The third event we analyze is the first strong event that looks hyperbolic: starting at some 0.4 seconds and bending down to some 2.2 seconds at 3200 m offset. Clearly, because of its hyperbolic behaviour, it is interpreted as a reflection. When looking at later times, we have some more strong hyperbolic events, such as at 0.8 seconds (bending downward toward some 2.3 seconds), and at 1.2 seconds (bending downward toward 2.4 seconds), and even more. These events are interpreted as so-called multiply reflected waves, i.e., waves that bounce up and down in the water layer. In fact almost all events we see below 0.8 seconds are due to multiply reflected waves, or short-hand: multiples. The times at which the multiply reflected waves arrive seem to be periodic; this is indeed the case. + +Combining the interpretation of the refraction and the reflection, it must be noted that the refracted arrival does not converge to the first reflection but to a later reflection. This means that the refraction occurs at a deeper layer; the shallower layers are probably loosely consolidated, so that the velocity of sound has not changed much compared to the one from water. + +A simple model explaining all these events is shown in the figure below the record, with a water layer of 300 meter. The refracted layer is estimated at a depth of 550 meter, where we assumed that the velocity was a constant of 1500 m/s above. The resulting synthetic seismogram is shown in the top right of the figure. It may be clear that the multiply reflected waves come from the same reflective boundary in the subsurface, namely, the sea bottom (and the sea surface, of course), and are therefore superfluous. They are considered as noise; the only one being "signal" is the one at around 0.4 seconds. + +```{figure} figures/Figure4_3.PNG +:name: fig-raw-shot-marine +:width: 100% + +Seismic wavefield recording from marine survey (top left), synthetic seismogram (top right) using model of water layer and sea-water bottom, where only the path of one multiple reflection is drawn (bottom). +``` diff --git a/book/4_mechanical_waves/figures/Figure4_1.PNG b/book/4_mechanical_waves/figures/Figure4_1.PNG new file mode 100644 index 0000000..dcc2ab1 Binary files /dev/null and b/book/4_mechanical_waves/figures/Figure4_1.PNG differ diff --git a/book/4_mechanical_waves/figures/Figure4_2.PNG b/book/4_mechanical_waves/figures/Figure4_2.PNG new file mode 100644 index 0000000..c1bf4c7 Binary files /dev/null and b/book/4_mechanical_waves/figures/Figure4_2.PNG differ diff --git a/book/4_mechanical_waves/figures/Figure4_3.PNG b/book/4_mechanical_waves/figures/Figure4_3.PNG new file mode 100644 index 0000000..1c4426f Binary files /dev/null and b/book/4_mechanical_waves/figures/Figure4_3.PNG differ diff --git a/book/4_mechanical_waves/figures/blokjes.png b/book/4_mechanical_waves/figures/blokjes.png new file mode 100644 index 0000000..49013f1 Binary files /dev/null and b/book/4_mechanical_waves/figures/blokjes.png differ diff --git a/book/4_mechanical_waves/figures/fig_ap_ac_cube.png b/book/4_mechanical_waves/figures/fig_ap_ac_cube.png new file mode 100644 index 0000000..efa8be4 Binary files /dev/null and b/book/4_mechanical_waves/figures/fig_ap_ac_cube.png differ diff --git a/book/4_mechanical_waves/figures/huygens.png b/book/4_mechanical_waves/figures/huygens.png new file mode 100644 index 0000000..c1fdd40 Binary files /dev/null and b/book/4_mechanical_waves/figures/huygens.png differ diff --git a/book/4_mechanical_waves/figures/pblock.PNG b/book/4_mechanical_waves/figures/pblock.PNG new file mode 100644 index 0000000..8159fac Binary files /dev/null and b/book/4_mechanical_waves/figures/pblock.PNG differ diff --git a/book/4_mechanical_waves/figures/ptens.PNG b/book/4_mechanical_waves/figures/ptens.PNG new file mode 100644 index 0000000..b66dd25 Binary files /dev/null and b/book/4_mechanical_waves/figures/ptens.PNG differ diff --git a/book/4_mechanical_waves/figures/rayelement.png b/book/4_mechanical_waves/figures/rayelement.png new file mode 100644 index 0000000..74e68fa Binary files /dev/null and b/book/4_mechanical_waves/figures/rayelement.png differ diff --git a/book/4_mechanical_waves/figures/rays.png b/book/4_mechanical_waves/figures/rays.png new file mode 100644 index 0000000..ef418c3 Binary files /dev/null and b/book/4_mechanical_waves/figures/rays.png differ diff --git a/book/4_mechanical_waves/figures/raytimes.png b/book/4_mechanical_waves/figures/raytimes.png new file mode 100644 index 0000000..2861c0e Binary files /dev/null and b/book/4_mechanical_waves/figures/raytimes.png differ diff --git a/book/4_mechanical_waves/figures/refltrans.png b/book/4_mechanical_waves/figures/refltrans.png new file mode 100644 index 0000000..7b00c37 Binary files /dev/null and b/book/4_mechanical_waves/figures/refltrans.png differ diff --git a/book/4_mechanical_waves/figures/sblock.PNG b/book/4_mechanical_waves/figures/sblock.PNG new file mode 100644 index 0000000..f064996 Binary files /dev/null and b/book/4_mechanical_waves/figures/sblock.PNG differ diff --git a/book/4_mechanical_waves/figures/seismicwave_1layer_vz.mp4 b/book/4_mechanical_waves/figures/seismicwave_1layer_vz.mp4 new file mode 100644 index 0000000..18a2de9 Binary files /dev/null and b/book/4_mechanical_waves/figures/seismicwave_1layer_vz.mp4 differ diff --git a/book/4_mechanical_waves/figures/snell.png b/book/4_mechanical_waves/figures/snell.png new file mode 100644 index 0000000..21b0b54 Binary files /dev/null and b/book/4_mechanical_waves/figures/snell.png differ diff --git a/book/4_mechanical_waves/figures/stens.PNG b/book/4_mechanical_waves/figures/stens.PNG new file mode 100644 index 0000000..ad3beb0 Binary files /dev/null and b/book/4_mechanical_waves/figures/stens.PNG differ diff --git a/book/4_mechanical_waves/figures/straindispl.PNG b/book/4_mechanical_waves/figures/straindispl.PNG new file mode 100644 index 0000000..a8fdbc2 Binary files /dev/null and b/book/4_mechanical_waves/figures/straindispl.PNG differ diff --git a/book/4_mechanical_waves/figures/stressforce.PNG b/book/4_mechanical_waves/figures/stressforce.PNG new file mode 100644 index 0000000..f0abae6 Binary files /dev/null and b/book/4_mechanical_waves/figures/stressforce.PNG differ diff --git a/book/4_mechanical_waves/figures/tautensor.PNG b/book/4_mechanical_waves/figures/tautensor.PNG new file mode 100644 index 0000000..323598f Binary files /dev/null and b/book/4_mechanical_waves/figures/tautensor.PNG differ diff --git a/book/4_mechanical_waves/fundamental_laws.md b/book/4_mechanical_waves/fundamental_laws.md new file mode 100644 index 0000000..2a71385 --- /dev/null +++ b/book/4_mechanical_waves/fundamental_laws.md @@ -0,0 +1,3 @@ +# Seismic wave fields from fundamental physical laws + +Above, we discussed the kinematic properties of wave motion, using rays and traveltimes, without worrying ourselves about the more fundamental laws that were behind it. Here we start from the physical fundamentals of mechanics, i.e., Newton's second law and deformation laws. Using these laws, we can derive the basic equations for wave motion, which then result in the so-called wave equation. The solution of the wave equation shows the features as discussed previously: it turns out that rays are obtained from the high-frequency approximation to that wave equation. The attenuation of the wave due to spreading is captured by the wave equation. And reflection and transmission amplitudes are also captured by applying the resulting equations describing the wave motion. So, here we will go into this, giving the fundamental backbone to the seismic wavefield recordings. diff --git a/book/4_mechanical_waves/intro.md b/book/4_mechanical_waves/intro.md index e69de29..f5293f5 100644 --- a/book/4_mechanical_waves/intro.md +++ b/book/4_mechanical_waves/intro.md @@ -0,0 +1,5 @@ +# Seismic wavefields + +In this chapter, we discuss seismic wave fields. We start from a kinematic point of view, including basic notions of wave fronts, rays, travel times, Huygens' principle and Snell's law at boundaries. Commonly, seismic wavefield measurements are taking place at the surface and then typically direct waves, reflected waves and critically-refracted/head waves are observed, and therefore considered here. Then, some typical wavefield recordings as observed on land and at sea are interpreted, in terms of these arrivals. From these events velocities and depths can be estimated. And from those, a first model for the subsurface is obtained (where the model is here seen as the interpretation of the wavefield data). + +Next, the seismic wave fields are discussed from a dynamic point of view. There we use the fundamental laws of Newton and Hooke to derive the basic equations describing seismic wave fields. From these the wave equation can be derived. Next, reflection and transmission coefficients at boundaries are derived. And finally elastic media with longitudinal (P) and shear (S) waves are considered and which equations describe their full dynamic behaviour. diff --git a/book/4_mechanical_waves/reflection_transmission.md b/book/4_mechanical_waves/reflection_transmission.md new file mode 100644 index 0000000..b7f348f --- /dev/null +++ b/book/4_mechanical_waves/reflection_transmission.md @@ -0,0 +1,83 @@ +(subsec-wavetheory)= +# Reflection and transmission at boundaries + +In this section, we will consider what happens at a boundary between two layers with different mechanical properties. Then we can show which characteristics are responsible for, e.g., a reflection. To that end, we will focus on the basic physical and theoretical principles of reflection and transmission in this section. The basic equations describing wave motion in one direction will be used to derive an expression for the reflection and transmission coefficient at a boundary between two layers with different wave speeds and densities. So in the movie we showed before (see again below), we consider only the part of the wave that is travelling purely downwards: it was already noticed that part of the wave is reflected at the boundary and part of it is transmitted. How much this is, and what it depends on, will be worked out below. + +```{video} figures/seismicwave_1layer_vz.mp4 +:width: 80% +``` + +In the previous section, the solution for the wave equation in the frequency domain was given, i.e.: + +$$ +P(x,\omega) = S(\omega) \exp (\pm i\omega x/c). +$$ + +```{figure} figures/refltrans.png +:name: fig-refltrans +:width: 60% + +Reflection and transmission at boundary between two media with different wave velocities $(c)$ and densities $(\rho)$. +``` + +Let us consider {numref}`fig-refltrans`. We defined a plane boundary between two regions with different wave speeds and mass densities. The boundary will reflect some of the energy back, and some will be transmitted. Above the boundary ($x<0$), we will have a so-called incident wave with some amplitude $S(\omega)$. In addition, we have a reflected wave above the boundary, which is travelling in the opposite direction as the incident field. This reflected field has a scaled version of the amplitude of the incident field. This scaling factor is called $R$, which is called the reflection coefficient. Below the boundary ($x>0$), we have a wave travelling in the same direction as the incident field, but has a scaled amplitude due to the transmission through the boundary. We call this amplitude $T$, which is the transmission coefficient. So, above the boundary ($x<0$), we have: + +$$ +P(x,\omega) = S(\omega) \exp(-i\omega x/c_1) + R S(\omega) \exp(i\omega x/c_1) +$$ + +Below the boundary ($x>0$), we have: + +$$ +P(x,\omega) = T S(\omega) \exp(-i\omega x/c_2) +$$ + +We have defined the reflection and transmission coefficient, but we still need to quantify them. This is achieved by posing the boundary conditions, which are that both the pressure and the particle velocity must be continuous, i.e.: + +$$ +\lim_{x \uparrow 0} P(x,\omega) = \lim_{x \downarrow 0} P(x,\omega) +$$ (eq:limitp) + +$$ +\lim_{x \uparrow 0} V_x(x,\omega) = \lim_{x \downarrow 0} V_x(x,\omega) +$$ (eq:limitv) + +The first boundary condition can be retrieved directly from the solutions for the pressure. However, for the second boundary condition, we need to use the equation of motion in its Fourier-transformed version, which is: + +$$ +V_x(x,\omega) = - \frac{1}{i\omega \rho} \frac{\partial P(x,\omega)}{\partial x} +$$ + +Working these out for the regions above and below the boundary, we obtain, respectively: + +$$ +\begin{aligned} +V_x(x,\omega) & = S(\omega) \frac{1}{\rho_1 c_1} \exp(-i\omega x/c_1) + - R S(\omega) \frac{1}{\rho_1 c_1} \exp(i\omega x/c_1) + & & \text{for } x < 0 \\ +V_x(x,\omega) & = T S(\omega) \frac{1}{\rho_2 c_2} \exp(-i\omega x/c_2) + & & \text{for } x > 0 +\end{aligned} +$$ + +Now we simply substitute the equations in the boundary conditions {eq}`eq:limitp` and {eq}`eq:limitv`, which give: + +$$ +\begin{aligned} +1 + R & = T +\\ +\frac{1}{\rho_1 c_1} - \frac{1}{\rho_1 c_1} R & = +\frac{1}{\rho_2 c_2} T. +\end{aligned} +$$ + +Working this out, we obtain for the reflection and transmission coefficients $R$ and $T$: + +$$ +\begin{aligned} +R & = \frac{\rho_2 c_2 - \rho_1 c_1}{\rho_2 c_2 + \rho_1 c_1} \\ +T & = \frac{2\rho_2 c_2}{\rho_2 c_2 + \rho_1 c_1} +\end{aligned} +$$ + +These are the desired expressions. First, notice that we have expressions in terms of seismic impedances, which are the product of the wave speed with the mass density, i.e., $\rho c$. Second, note that the reflection coefficient is determined by the *contrast in the seismic impedances of the different regions*. diff --git a/book/4_mechanical_waves/snells_law.md b/book/4_mechanical_waves/snells_law.md new file mode 100644 index 0000000..6007e0c --- /dev/null +++ b/book/4_mechanical_waves/snells_law.md @@ -0,0 +1,160 @@ +(subsec-basickinematics)= +# The interface: Snell's law, refraction and reflection + +So far, we discussed waves in a material which everywhere had the same constant wave velocity. When we include a boundary between two different materials, some energy is bounced back, or reflected, and some energy is going through to the other medium. It is nice to perform Huygens' principle graphically on such a configuration to see how the wave field moves forward (propagates), especially into the second medium. From this picture, we could also derive the ray concept. In this discussion, we will only consider the notion of rays. A basic notion in the ray concept, is Snell's law. Snell's law is a fundamental relation in the seismic wave fields. It tells us the relation between angle of incidence of a wave and velocity in two adjacent layers (see {numref}`fig-snellslaw`). + +```{figure} figures/snell.png +:name: fig-snellslaw +:width: 70% + +Transmission through a boundary (for deriving Snell's law). +``` + +$AA'A''$ is part of a plane wave incident at angle $\theta_1$ to a plane interface between medium 1 of velocity $c_1,$ and medium 2 of velocity $c_2.$ Velocities $c_1$ and $c_2$ are constant. In a time $t$ the wave front $AA'$ moves to the position $BB'$ and the movement is normal to the wave front. Then, the time $t$ it takes to travel from $A'$ to $B'$ in medium 1 is equal to the time from $A$ to $B$ in medium 2, so + +$$ +t = \frac{A'B'}{c_1} = \frac{AB}{c_2} +$$ + +Considering the two triangles, this may be written as: + +$$ +t = \frac{AB' \sin \theta_1}{c_1} = \frac{AB' \sin \theta_2}{c_2} +$$ + +Hence, + +$$ +\frac{\sin \theta_1}{c_1} = \frac{\sin \theta_2}{c_2} +$$ + +which is Snell's law for transmission through a boundary between two layers with different velocities. So far, we have taken general velocities $c_1$ and $c_2$. However, in a solid, two velocities exist, namely P- and S-wave velocities. Generally, when a P-wave is incident on a boundary, it can transmit as a P-wave into the second medium, but also as a S-wave. So in the case of the latter, Snell's law reads: + +$$ +\frac{\sin \theta_P}{c_P} = \frac{\sin \theta_S}{c_S} +$$ + +where $c_P$ is the P-wave velocity, and $c_S$ the S-wave velocity. The same holds for reflection: a P-wave incident on the boundary generates a reflected P-wave and a reflected S-wave. Finally, the same holds for an incident S-wave: it generates a reflected P-wave, a reflected S-wave, a transmitted P-wave and a transmitted S-wave. + +A special case of Snell's law is of interest in refraction prospecting. If the ray is critically refracted along the interface (that is, if $\theta_2 = 90^\circ$), we have + +$$ +\frac{\sin \theta_c}{c_1} = \frac{1}{c_2} +$$ + +where $\theta_c$ is known as the critical angle. + +So far, we have looked at the basic notions of refraction and reflection at an interface. When we measure in the field, and there would be one boundary below it, we could observe several arrivals: a direct ray, a reflected ray, and a refracted ray. We will derive the arrival time of each ray as depicted in {numref}`fig-rays`. + +```{figure} figures/rays.png +:name: fig-rays +:width: 80% + +The paths of the direct, reflected and refracted rays. +``` + +The arrival time of the direct ray is very simple: it is the horizontal distance divided by the velocity of the wave, i.e.,: + +$$ +t = \frac{x}{c_1}, +$$ + +so in a time-distance graph this is a linear event. + +When we look at the reflected ray, we find that the angle of incidence is the same as the angle of reflection. This also follows from Snell's law: when the velocities are the same, the angles must also be the same. When we use Pythagoras' theorem, we obtain the following for the traveltime: + +$$ +t = \frac{ \left( 4z^2+x^2 \right)^{1/2} }{c_1} +$$ + +Squaring this equation: + +$$ +t^2 = \left( \frac{2z}{c_1} \right)^2 + \left( \frac{x}{c_1} \right)^2 , +$$ + +or + +$$ +t^2 - \left( \frac{x}{c_1} \right)^2 = \left( \frac{2z}{c_1} \right)^2, +$$ + +so for a time-distance $(t-x)$ graph this is the equation of a hyperbola. + +When we look at the refracted ray, the derivation is a bit more complicated. Take each ray element; therefore, take the paths $AB,$ $BC$ and $CD$ separately. Then, for the first element, as shown in {numref}`fig-rayelement`, we obtain the traveltime: + +$$ +\Delta t_1 = \frac{\Delta s_1 + \Delta s_2}{c_1} = +\frac{\Delta x_1 \sin \theta_c}{c_1} + \frac{z \cos \theta_c}{c_1} +$$ + +where $\theta_c$ is the critical angle. + +```{figure} figures/rayelement.png +:name: fig-rayelement +:width: 60% + +An element of the ray with critical incidence. +``` + +We can also do this for the paths $BC$ and $CD$, and we obtain the total time as: + +$$ +\begin{aligned} +t & = \Delta t_1 + \Delta t_2 + \Delta t_3 \\ + & = \frac{\Delta x_1 \sin \theta_c}{c_1} + \frac{z \cos \theta_c}{c_1} + + \frac{\Delta x_2}{c_2} + + \frac{\Delta x_3 \sin \theta_c}{c_1} + \frac{z \cos \theta_c}{c_1} +\end{aligned} +$$ + +where $\Delta x_2 = BC$ and $\Delta x_3$ is the horizontal distance between $C$ and $D$. When we now use Snell's law, i.e., $\sin \theta_c /c_1=1/c_2,$ in terms with $\Delta x_1$ and $\Delta x_3,$ then we can add all the terms with $1/c_2,$ using $x = \Delta x_1 + \Delta x_2 + \Delta x_3$ to obtain: + +$$ +t = \frac{x}{c_2} + \frac{2z \cos \theta_c}{c_1} +$$ (eq:trefract) + +We recognize this equation as the equation of a straight line when $t$ is considered as a function of the distance $x,$ the line along which we do our wavefield measurements. + +We have now derived the equations for the three rays, and we can plot their travel times as a function of distance $x$. This is done in {numref}`fig-raytimes`. This picture is important. When we measure seismic data in the field, the characteristics in this plot can be observed most of the time. + +We considered travel times, but they are a result of a seismic wave field propagating in the subsurface. To get an idea of how a wave moves, we consider the movie below. A seismic source initiates a seismic wave at the top and the wave propagates outward (on a circle, for a homogeneous medium). Then later the wave encounters a boundary at which part of the wave is reflected and part of it is transmitted into the lower medium. There it travels with a higher speed; it can be seen that the wave travels faster along the boundary there. Then, part of it is diffracted back into the first medium (quite faint): that is the head wave, or critically refracted ray. + +```{video} figures/seismicwave_1layer_vz.mp4 +:width: 80% +``` + +```{figure} figures/raytimes.png +:name: fig-raytimes +:width: 60% + +Time-distance $(t,x)$ curve for the direct, reflected and refracted rays. +``` + +Based on this figure, we can specify better when we can expect reflections or refractions. In refraction seismics we are interested in the critically refracted waves, and then only in the travel times. This means that we can only observe the traveltimes well if it is not masked by reflections and/or direct waves, which means that we must measure at a relatively large distance with respect to the depth of interest. This is different for reflection seismics. There, the reflections will always be masked by refractions and/or direct waves, but there are ways to enhance the reflections. What we are interested in is the arrival at relatively small offsets, thus distances of the sound source to the detector, which are small with respect to the depth we are interested in. + +Before discussing any more differences between the refraction method and the reflection method, we would like to discuss the amplitude effects at the boundary. Let us first introduce the acoustic impedance, which is the product of the density $\rho$ with the wave velocity $c,$ i.e., $\rho c.$ When a ray encounters a boundary, some wavefield energy will be reflected back, and some will be transmitted to the next layer. The amount of energy reflected back is characterized by the reflection coefficient $R$: + +$$ +R = \frac{\rho_2 c_2 - \rho_1 c_1}{\rho_2 c_2 + \rho_1 c_1} +$$ + +That this is the case, will be derived from basic physical principles in a later section on wave theory. Obviously, the larger the impedance contrast between two layers, the higher the amplitude of the reflected wave. Notice that it is the impedance contrast that determines whether energy is reflected back or not; it may happen that the velocities and densities are different between two layers, but that the impedances are (nearly) the same. In that case, we will not see a reflection. We can now state another difference between refraction and reflection seismics. With refraction seismics we are only interested in traveltimes of the waves, so this means that we are interested in contrasts in velocities. This is different in reflection seismics. Then we are interested in the amplitude of the waves, and we will only measure an amplitude if there is a contrast in acoustic impedance in the subsurface. + +Finally, we tabulate the most important differences between reflection and refraction seismic in {numref}`tab-diffref`. + +```{list-table} Important differences between refraction and reflection seismics. +:name: tab-diffref +:header-rows: 1 + +* - **REFRACTION SEISMICS** + - **REFLECTION SEISMICS** +* - Based on contrasts in: seismic wave speed $(c)$ + - Based on contrasts in: seismic wave impedances $(\rho c)$ +* - Material property determined: wave speed only + - Material properties determined: wave speed and wave impedance +* - Only traveltimes used + - Traveltimes and amplitudes used +* - Source-receiver distances large compared to investigation depth + - Source-receiver distances small compared to investigation depth +``` diff --git a/book/4_mechanical_waves/wave_equation_solutions.md b/book/4_mechanical_waves/wave_equation_solutions.md new file mode 100644 index 0000000..459ad4d --- /dev/null +++ b/book/4_mechanical_waves/wave_equation_solutions.md @@ -0,0 +1,48 @@ +# Solution(s) to the wave equation + +The solution to the wave equation for the pressure is: + +$$ +p(x,t) = s(t \pm x/c) +$$ (eq:pxt) + +where $s(t)$ is some function. Note the dependency on space and time via $(t \pm x/c)$, which denotes that it is a travelling wave, and behaves as a direct wave as discussed in [](./snells_law.md). The sign in the argument depends on the direction the wave is travelling. + +Often, seismic responses are analyzed in terms of frequencies, i.e., Fourier spectra. The definition used here is: + +$$ +G(\omega) = \int_{-\infty}^{+\infty} g(t) \exp(- i \omega t) \, dt +$$ (eq:fourier1) + +where the radial frequency $\omega$ is used, so $\omega = 2 \pi f$ where $f$ is the (ordinary) frequency. Using this convention, it is easy to show that differentiation with respect to time is equivalent to multiplication with $i\omega$ in the Fourier domain. When we transform the solution of the wave equation ({eq}`eq:pxt`) to the Fourier domain, we obtain: + +$$ +P(x,\omega) = S(\omega) \exp (\pm i\omega x/c). +$$ (eq:Pxw) + +Note here that the time delay $x/c$ (in the time domain) becomes a *linear* phase in the Fourier domain, so the phase $\pm \omega x/c$ is linear as a function of $\omega$. + +In the above, we gave an expression for the pressure, but one can also derive an equivalent expression for the particle velocity $v_x$. For that purpose, we can use the equation of motion as expressed in {eq}`eq:eqmotion`, but then in its Fourier-transformed version, which is: + +$$ +V_x(x,\omega) = -\frac{1}{i\omega \rho} \frac{\partial P(x,\omega)}{\partial x}. +$$ + +When we substitute the solution for the pressure from above ({eq}`eq:Pxw`), we get for the negative sign: + +$$ +\begin{aligned} +V_x(x,\omega) & = -\frac{1}{i \omega \rho} + S(\omega) \frac{- i \omega}{c} \exp(-i\omega x/c) +\\ + & = S(\omega) \frac{1}{\rho c} \exp(-i\omega x/c). +\end{aligned} +$$ + +Notice that the particle velocity is a scaled version of the pressure: + +$$ +V_x(x,\omega) = \frac{P(x,\omega)}{\rho c}. +$$ + +The scaling factor is ($\rho c$), being called the *seismic impedance*. diff --git a/book/_toc.yml b/book/_toc.yml index c509667..5389490 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -65,8 +65,11 @@ parts: - file: 2_potential_fields/magnetic_field/exercises.md - file: 2_potential_fields/labs/week3_gravity_and_potential/week3_exersizes.md - file: 2_potential_fields/labs/week3_gravity_and_potential/week3_exersizes_solutions.md + - file: 2_potential_fields/labs/week4/week4_quiz.md + - file: 2_potential_fields/labs/week4/week4_quiz_solutions.md + - file: 2_potential_fields/labs/week4/week4_exercises.md + - file: 2_potential_fields/labs/week4/week4_exercises_solutions.md # - file: 2_potential_fields/gradient_fields.md - # - file: 2_potential_fields/divergence_free_fields.md # - file: 2_potential_fields/curl_free_fields.md # - caption: Exercises # chapters: @@ -96,6 +99,31 @@ parts: # - file: extension_exercises/014.md # - file: extension_exercises/015.md # - file: extension_exercises/016.md + - caption: Diffusive fields + chapters: + - file: 3_diffusion_fields/intro.md + sections: + - file: 3_diffusion_fields/heat_equation_1d.md + - file: 3_diffusion_fields/em_diffusion.md + - file: 3_diffusion_fields/labs/week05_diffusion.md + - file: 3_diffusion_fields/labs/week06_em_diffusion.md + - caption: Mechanical waves + chapters: + - file: 4_mechanical_waves/intro.md + sections: + - file: 4_mechanical_waves/basic_notions.md + - file: 4_mechanical_waves/snells_law.md + - file: 4_mechanical_waves/exercise_4a.md + - file: 4_mechanical_waves/field_recordings.md + - file: 4_mechanical_waves/exercise_4b.md + # - file: 4_mechanical_waves/fundamental_laws.md + # - file: 4_mechanical_waves/acoustic_waves.md + # - file: 4_mechanical_waves/wave_equation_solutions.md + # - file: 4_mechanical_waves/reflection_transmission.md + # - file: 4_mechanical_waves/elastic_waves.md + # - file: 4_mechanical_waves/exercises.md + # - file: 4_mechanical_waves/appendix_acoustic_1d.md + # - file: 4_mechanical_waves/appendix_strain_p_s.md - caption: Miscellaneous chapters: - file: references.md diff --git a/book/credits.md b/book/credits.md index 924bdc7..e774042 100644 --- a/book/credits.md +++ b/book/credits.md @@ -21,31 +21,6 @@ To recreate the website you have two options (more information in the [TeachBook ## License This book is [CC BY 4.0 licensed](https://creativecommons.org/licenses/by/4.0/) allowing you to share and adapt the material, as long as the source is named. External resources that are reused in this book are listed below. -(external_resources)= -### External resources - -Parts of this book are taken from other external resources and reused in various ways. If an author is not listed on a particular page, it is by the Authors, except as follows: - -The following pages are included directly from an external resource and are not edited by the course team: -- The following pages includes text from {cite:t}`template`. Original content licensed under CC BY 4.0 License: - - [](./exercises.md) - - [](./exercises/002.md) - - [](./exercises/003.md) - - [](./exercises/004.md) - - [](./exercises/005.md) - - [](./exercises/006.md) - - [](./syntax_exercises.md) - - [](./syntax_exercises/007.md) - - [](./syntax_exercises/008.md) - - [](./syntax_exercises/009.md) - - [](./syntax_exercises/010.md) - - [](./syntax_exercises/011.md) - - [](./exercises/summary.md) - -The following pages contain content written by others, part of which has been reused and/or modified by the course team: -- Page [](./exercises/001.md) includes text from {cite:t}`template` and is edited to be made TU Delft-specific. Original content licensed under CC BY 4.0 License. -- Page [](./syntax_exercises/012.md) includes text from {cite:t}`template` and is edited to be made TU Delft-specific. Original content licensed under CC BY 4.0 License. - (editor)= ## About the Editors diff --git a/book/intro.md b/book/intro.md index 400ed64..2131c2f 100644 --- a/book/intro.md +++ b/book/intro.md @@ -7,12 +7,14 @@ title: ECTB2140 Fields and Waves 2026 :::{admonition} This book is under development :class: warning -The book is being written during the 2026-2027 run of ECTB2140, and the material is incomplete beyond the first chapter. +The book is being written during the 2026-2027 run of ECTB2140, and the material is incomplete. -- **Chapter 1, Gradient, divergence and curl**, is complete: the lecture notes and both computer labs. +- **Chapter 1, Gradient, divergence and curl**, is complete. - **Chapter 2, Potential fields**, is partly written. +- **Chapter 3, Diffusion fields**, is partly written. +- **Chapter 4, Mechanical waves**, is partly written. - Later chapters are not yet available here. -- The **Exercises** section in the sidebar is left over from the book template. It explains how TeachBooks works and is not course material. + Brightspace remains the authoritative source for the schedule, assessment and announcements. Pages here change between weeks, so download a notebook again rather than relying on a copy saved earlier. :::