|
27 | 27 | Computing derivatives |
28 | 28 | ^^^^^^^^^^^^^^^^^^^^^ |
29 | 29 |
|
30 | | -Given a PDE and its Green's function, we want to compute the :math:`n`-th |
31 | | -derivative :math:`\partial^n G / \partial x_1^n` at a point |
32 | | -:math:`(x_1, x_2, \dots)`. Here :math:`x_1` is the first coordinate |
33 | | -(called ``x0`` in the 0-indexed code variables). |
| 30 | +Given a PDE and its Green's function |
| 31 | +:math:`G(\boldsymbol x, \boldsymbol t)` where |
| 32 | +:math:`\boldsymbol x = (x_1, x_2, \dots)`, we want to compute the |
| 33 | +:math:`n`-th derivative :math:`\partial^n G / \partial x_1^n` with |
| 34 | +respect to the first coordinate :math:`x_1` of :math:`\boldsymbol x` |
| 35 | +(called ``x0`` in the 0-indexed code variables), with |
| 36 | +:math:`\boldsymbol t` fixed. |
34 | 37 |
|
35 | 38 | There are two regimes, selected based on the relative magnitude of |
36 | 39 | :math:`|x_1|`: |
|
77 | 80 | Example: large-:math:`|x_1|` recurrence |
78 | 81 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
79 | 82 |
|
| 83 | +We compute |
| 84 | +
|
| 85 | +.. math:: |
| 86 | +
|
| 87 | + s(n) = \frac{\partial^n}{\partial x_1^n} |
| 88 | + G(\boldsymbol x, \boldsymbol t)\Big|_{\boldsymbol t=0}, |
| 89 | + \qquad n = 0, 1, \dots, p |
| 90 | +
|
| 91 | +for the 2D Laplace Green's function |
| 92 | +
|
| 93 | +.. math:: |
| 94 | +
|
| 95 | + G(\boldsymbol x, \boldsymbol t) |
| 96 | + = -\frac{1}{2\pi}\log|\boldsymbol x - \boldsymbol t| |
| 97 | +
|
| 98 | +evaluated at the point :math:`\boldsymbol x = (0.5, 0.3)` with |
| 99 | +the target fixed at the origin :math:`\boldsymbol t = 0`. |
| 100 | +
|
80 | 101 | .. code-block:: python |
81 | 102 |
|
| 103 | + import numpy as np |
82 | 104 | import sympy as sp |
83 | 105 | from sumpy.expansion.diff_op import laplacian, make_identity_diff_op |
84 | 106 | from sumpy.recurrence import get_large_x1_recurrence, _make_sympy_vec |
|
89 | 111 |
|
90 | 112 | # 2. Get recurrence |
91 | 113 | n_initial, order, recurrence = get_large_x1_recurrence(pde) |
92 | | - # n_initial: number of initial derivatives to seed directly |
93 | | - # order: recurrence order (how many prior values s(n) depends on) |
94 | | - # recurrence: sympy expression giving s(n) in terms of s(n-1), ... |
95 | 114 |
|
96 | | - # 3. Compute derivatives at point (x0, x1) = (0.5, 0.3) |
| 115 | + # 3. Define G(x, t) and the evaluation point |
| 116 | + var = _make_sympy_vec("x", 2) # source coordinates |
| 117 | + var_t = _make_sympy_vec("t", 2) # target coordinates |
| 118 | + g = (-1/(2*np.pi)) * sp.log(sp.sqrt((var[0]-var_t[0])**2 |
| 119 | + + (var[1]-var_t[1])**2)) |
| 120 | +
|
97 | 121 | n = sp.symbols("n") |
98 | 122 | s = sp.Function("s") |
99 | | - var = _make_sympy_vec("x", 2) |
| 123 | + # Evaluate at source x = (0.5, 0.3), target t = 0 |
100 | 124 | x_vals = [(var[0], sp.Rational(1, 2)), (var[1], sp.Rational(3, 10))] |
101 | 125 |
|
102 | | - # Seed initial conditions by direct differentiation of G |
103 | | - import numpy as np |
104 | | - var_t = _make_sympy_vec("t", 2) |
105 | | - g = (-1/(2*np.pi)) * sp.log(sp.sqrt((var[0]-var_t[0])**2 |
106 | | - + (var[1]-var_t[1])**2)) |
| 126 | + # 4. Seed initial derivatives by direct differentiation of G(x, 0) |
107 | 127 | derivs = {} |
108 | 128 | for i in range(-order, 0): |
109 | 129 | derivs[i] = 0j |
110 | 130 | for i in range(n_initial): |
111 | 131 | d = sp.diff(g, var[0], i) |
112 | 132 | for j in range(2): |
113 | | - d = d.subs(var_t[j], 0) |
| 133 | + d = d.subs(var_t[j], 0) # fix target at origin |
114 | 134 | derivs[i] = complex(d.subs(x_vals)) |
115 | 135 |
|
116 | | - # Apply recurrence up to order p |
| 136 | + # 5. Apply recurrence to get derivatives up to order p |
117 | 137 | p = 8 |
118 | 138 | for i in range(n_initial, p + 1): |
119 | 139 | expr = recurrence.subs(n, i) |
|
124 | 144 | Example: small-:math:`|x_1|` expansion |
125 | 145 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
126 | 146 |
|
| 147 | +Continuing from the same setup above, we now compute the same derivatives |
| 148 | +via the small-:math:`|x_1|` path. The small-:math:`|x_1|` recurrence |
| 149 | +first computes the Taylor coefficients |
| 150 | +
|
| 151 | +.. math:: |
| 152 | +
|
| 153 | + c(n) = \frac{\partial^n}{\partial x_1^n} |
| 154 | + G(\boldsymbol x, \boldsymbol t)\Big|_{\boldsymbol t=0,\; x_1=0} |
| 155 | +
|
| 156 | +i.e. the derivatives evaluated at the point :math:`(0, 0.3)`. |
| 157 | +The expansion then recovers the derivative at the full point |
| 158 | +:math:`\boldsymbol x = (0.5, 0.3)` via a truncated Taylor series |
| 159 | +in :math:`x_1`: |
| 160 | +
|
| 161 | +.. math:: |
| 162 | +
|
| 163 | + s(n) = \frac{\partial^n}{\partial x_1^n} |
| 164 | + G(\boldsymbol x, \boldsymbol t)\Big|_{\boldsymbol t=0} |
| 165 | + \approx \sum_{k=0}^{K} \frac{c(n+k)}{k!}\, x_1^k |
| 166 | +
|
| 167 | +where :math:`K` is the user-chosen truncation order. |
| 168 | +
|
127 | 169 | .. code-block:: python |
128 | 170 |
|
129 | 171 | from sumpy.recurrence import get_small_x1_recurrence, get_small_x1_expansion |
|
135 | 177 | taylor_order = 8 |
136 | 178 | expansion, n_coeffs, start_order = get_small_x1_expansion( |
137 | 179 | pde, taylor_order) |
138 | | - # expansion: sympy expression in s(n), s(n-1), ..., and x0 |
139 | | - # n_coeffs: number of prior recurrence values needed |
140 | | - # start_order: minimum n at which the expansion is valid |
141 | 180 |
|
142 | | - # 3. Compute Taylor coefficients via the small-|x_1| recurrence |
143 | | - # (these are derivatives evaluated at x_1=0) |
| 181 | + # 3. Compute Taylor coefficients: derivatives of G(x, 0) at x_1=0 |
144 | 182 | coeffs = {} |
145 | 183 | for i in range(-recur_order, 0): |
146 | 184 | coeffs[i] = 0j |
147 | 185 | for i in range(start_order): |
148 | | - # Seed by direct differentiation of G at x0=0 |
149 | 186 | d = sp.diff(g, var[0], i) |
150 | 187 | for j in range(2): |
151 | | - d = d.subs(var_t[j], 0) |
152 | | - coeffs[i] = complex(d.subs(var[0], 0).subs(x_vals)) |
| 188 | + d = d.subs(var_t[j], 0) # fix target at origin |
| 189 | + coeffs[i] = complex(d.subs(var[0], 0).subs(x_vals)) # then set x_1=0 |
153 | 190 | for i in range(start_order, p + 1): |
154 | 191 | expr = recur.subs(n, i) |
155 | 192 | for j in range(recur_order, 0, -1): |
156 | 193 | expr = expr.subs(s(i - j), coeffs[i - j]) |
157 | 194 | coeffs[i] = complex(expr.subs(x_vals)) |
158 | 195 |
|
159 | | - # 4. Evaluate the expansion at a point with small x_1 |
| 196 | + # 4. Evaluate the expansion at x = (0.5, 0.3) |
160 | 197 | for i in range(start_order, p + 1): |
161 | 198 | expr = expansion.subs(n, i) |
162 | 199 | for j in range(n_coeffs, -1, -1): |
|
0 commit comments