diff --git a/docs/user-guide/vector_calculus.ipynb b/docs/user-guide/vector_calculus.ipynb index af411e816..831e7391b 100644 --- a/docs/user-guide/vector_calculus.ipynb +++ b/docs/user-guide/vector_calculus.ipynb @@ -321,7 +321,7 @@ "source": [ "### Example 1: Curl of Gradient Field\n", "\n", - "A fundamental vector identity states that the curl of any gradient field should be zero (conservative field). Let's verify this:" + "In the continuous setting, curl(∇φ) = 0 exactly for any scalar field φ. On an unstructured mesh, however, gradient and curl are independent finite-volume stencils that do not form a discrete de Rham complex, so the identity holds only approximately. The residual is a **discretization error** — not a bug — and shrinks with grid refinement (O(Δx) for first-order stencils). For a Gaussian field on a coarse mesh the residual is typically O(1–10), consistent with the grid spacing.\n" ] }, { @@ -690,8 +690,8 @@ "\n", "Let's verify some fundamental vector calculus identities using our computed fields:\n", "\n", - "### Identity 1: Curl of Gradient is Zero\n", - "For any scalar field φ: ∇ × (∇φ) = 0" + "### Identity 1: Curl of Gradient (Discretization Residual)\n", + "In the continuous setting: ∇ × (∇φ) = 0. UXarray's finite-volume operators are not mimetic, so this holds only approximately. The residual below is discretization error, not a numerical bug.\n" ] }, { @@ -704,7 +704,10 @@ "# We already computed this above\n", "max_curl_grad = np.abs(curl_of_gradient).max().values\n", "print(f\"Maximum |curl(∇φ)|: {max_curl_grad:.2e}\")\n", - "print(f\"Identity verified: {max_curl_grad < 1e-10}\")" + "print(\n", + " \"Note: non-zero residual is expected discretization error from independent \"\n", + " \"finite-volume gradient and curl stencils (not a bug). Shrinks with grid refinement.\"\n", + ")" ] }, {