Skip to content

Commit fa7c8e0

Browse files
committed
Created plots for recurrenceqbx
1 parent 0614ff1 commit fa7c8e0

6 files changed

Lines changed: 178 additions & 83 deletions

File tree

sumpy/recurrence.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ def _get_initial_order_off_axis(recurrence):
374374

375375
i = 0
376376
r_c = recurrence.subs(n, i)
377-
while _check_neg_ind(r_c) or r_c == 0:
377+
while (_check_neg_ind(r_c) or r_c == 0) or i % 2 != 0:
378378
i += 1
379379
r_c = recurrence.subs(n, i)
380380
return i
@@ -455,15 +455,6 @@ def get_reindexed_and_center_origin_off_axis_recurrence(pde: LinearPDESystemOper
455455
"""
456456
var = _make_sympy_vec("x", 1)
457457
r_exp = _move_center_origin_source_arbitrary_expression(pde).subs(var[0], 0)
458-
459-
var = _make_sympy_vec("x", 2)
460-
var_t = _make_sympy_vec("t", 2)
461-
g_x_y = sp.log(sp.sqrt((var[0]-var_t[0])**2 + (var[1]-var_t[1])**2))
462-
derivs = [sp.diff(g_x_y,
463-
var_t[0], i).subs(var_t[0], 0).subs(var_t[1], 0)
464-
for i in range(8)]
465-
466-
467458
recur_order, recur = reindex_recurrence_relation(r_exp)
468459
start_order = _get_initial_order_off_axis(recur)
469460
return start_order, recur_order, recur

sumpy/recurrence_qbx.py

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def _compute_rotated_shifted_coordinates(
7777

7878
# ================ Recurrence LP Eval =================
7979
def recurrence_qbx_lp(sources, centers, normals, strengths, radius, pde, g_x_y,
80-
ndim, p) -> np.ndarray:
80+
ndim, p, off_axis_start=0) -> np.ndarray:
8181
r"""
8282
A function that computes a single-layer potential using a recurrence.
8383
@@ -130,8 +130,9 @@ def generate_lamb_expr(i, n_initial):
130130
#print(lamb_expr_symb)
131131
return sp.lambdify(arg_list, lamb_expr_symb)#, sp.lambdify(arg_list, lamb_expr_symb_deriv)
132132

133-
interactions_on_axis = 0
133+
134134
coord = [cts_r_s[j] for j in range(ndim)]
135+
interactions_on_axis = coord[0] * 0
135136
for i in range(p+1):
136137
lamb_expr = generate_lamb_expr(i, n_initial)
137138
a = [*storage, *coord]
@@ -156,6 +157,8 @@ def generate_lamb_expr(i, n_initial):
156157
t_exp, t_exp_order, _ = get_off_axis_expression(pde, 8)
157158
storage_taylor_order = max(t_recur_order, t_exp_order+1)
158159

160+
start_order = max(start_order, order)
161+
159162
storage_taylor = [np.zeros((n_p, n_p))] * storage_taylor_order
160163
def gen_lamb_expr_t_recur(i, start_order):
161164
arg_list = []
@@ -210,6 +213,7 @@ def gen_lamb_expr_t_exp(i, t_exp_order, start_order):
210213

211214
################
212215
# Compute True Interactions
216+
'''
213217
storage_taylor_true = [np.zeros((n_p, n_p))] * storage_taylor_order
214218
def generate_true(i):
215219
arg_list = []
@@ -231,32 +235,33 @@ def generate_true(i):
231235
a4 = [*coord]
232236
s_new_true = lamb_expr_true(*a4)
233237
interactions_true += s_new_true * radius**i/math.factorial(i)
238+
'''
234239
###############
235240

236241
#slope of line y = mx
237242
m = 100
238243
mask_on_axis = m*np.abs(coord[0]) >= np.abs(coord[1])
239244
mask_off_axis = m*np.abs(coord[0]) < np.abs(coord[1])
240245

241-
print("-------------------------")
246+
#print("-------------------------")
242247

243-
percent_on = np.sum(mask_on_axis)/(mask_on_axis.shape[0]*mask_on_axis.shape[1])
244-
percent_off = 1-percent_on
248+
#percent_on = np.sum(mask_on_axis)/(mask_on_axis.shape[0]*mask_on_axis.shape[1])
249+
#percent_off = 1-percent_on
245250

246-
relerr_on = np.abs(interactions_on_axis[mask_on_axis]-interactions_true[mask_on_axis])/np.abs(interactions_on_axis[mask_on_axis])
247-
print("MAX ON AXIS ERROR(", percent_on, "):", np.max(relerr_on))
248-
print(np.mean(relerr_on))
249-
print("X:", coord[0][mask_on_axis].reshape(-1)[np.argmax(relerr_on)])
250-
print("Y:", coord[1][mask_on_axis].reshape(-1)[np.argmax(relerr_on)])
251+
#relerr_on = np.abs(interactions_on_axis[mask_on_axis]-interactions_true[mask_on_axis])/np.abs(interactions_on_axis[mask_on_axis])
252+
#print("MAX ON AXIS ERROR(", percent_on, "):", np.max(relerr_on))
253+
#print(np.mean(relerr_on))
254+
#print("X:", coord[0][mask_on_axis].reshape(-1)[np.argmax(relerr_on)])
255+
#print("Y:", coord[1][mask_on_axis].reshape(-1)[np.argmax(relerr_on)])
251256

252-
print("-------------------------")
257+
#print("-------------------------")
253258

254-
if np.any(mask_off_axis):
255-
relerr_off = np.abs(interactions_off_axis[mask_off_axis]-interactions_true[mask_off_axis])/np.abs(interactions_off_axis[mask_off_axis])
256-
print("MAX OFF AXIS ERROR(", percent_off, "):", np.max(relerr_off))
257-
print(np.mean(relerr_off))
258-
print("X:", coord[0][mask_off_axis].reshape(-1)[np.argmax(relerr_off)])
259-
print("Y:", coord[1][mask_off_axis].reshape(-1)[np.argmax(relerr_off)])
259+
#if np.any(mask_off_axis):
260+
# relerr_off = np.abs(interactions_off_axis[mask_off_axis]-interactions_true[mask_off_axis])/np.abs(interactions_off_axis[mask_off_axis])
261+
# print("MAX OFF AXIS ERROR(", percent_off, "):", np.max(relerr_off))
262+
# print(np.mean(relerr_off))
263+
# print("X:", coord[0][mask_off_axis].reshape(-1)[np.argmax(relerr_off)])
264+
# print("Y:", coord[1][mask_off_axis].reshape(-1)[np.argmax(relerr_off)])
260265

261266
interactions_total = np.zeros(coord[0].shape)
262267
interactions_total[mask_on_axis] = interactions_on_axis[mask_on_axis]

test/investigate_normal_recurrence.ipynb

Lines changed: 61 additions & 32 deletions
Large diffs are not rendered by default.

test/plotting.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ def generate_lamb_expr(i, n_initial):
8686
t_exp, t_exp_order, _ = get_off_axis_expression(pde, 8)
8787
storage_taylor_order = max(t_recur_order, t_exp_order+1)
8888

89+
start_order = max(start_order, order)
90+
8991
storage_taylor = [np.zeros((1, n_p))] * storage_taylor_order
9092
def gen_lamb_expr_t_recur(i, start_order):
9193
arg_list = []
@@ -95,7 +97,7 @@ def gen_lamb_expr_t_recur(i, start_order):
9597
for j in range(ndim):
9698
arg_list.append(var[j])
9799

98-
if i < start_order+4:
100+
if i < start_order:
99101
lamb_expr_symb_deriv = sp.diff(g_x_y, var_t[0], i)
100102
for j in range(ndim):
101103
lamb_expr_symb_deriv = lamb_expr_symb_deriv.subs(var_t[j], 0)
@@ -267,12 +269,12 @@ def create_suite_plot(relerr_on, relerr_off, relerr_comb, str_title):
267269

268270

269271
#======================== BIHARMONIC 2D ===================================
270-
interactions_on_axis, interactions_off_axis, interactions_true, interactions_total = produce_error_for_recurrences(mesh_points, biharmonic_pde, g_x_y_biharmonic, 7)
272+
interactions_on_axis, interactions_off_axis, interactions_true, interactions_total = produce_error_for_recurrences(mesh_points, biharmonic_pde, g_x_y_biharmonic, 12, m=1e2/2)
271273

272274
relerr_on = np.abs((interactions_on_axis-interactions_true)/interactions_true)
273275
relerr_off = np.abs((interactions_off_axis-interactions_true)/interactions_true)
274276
relerr_comb = np.abs((interactions_total-interactions_true)/interactions_true)
275277

276-
create_suite_plot(relerr_on, relerr_off+1e-20, relerr_comb+1e-20, "Biharmonic 2D: 7th Order Derivative Evaluation Error $(u_{recur}-u_{sympy})/u_{recur}$")
278+
create_suite_plot(relerr_on+1e-20, relerr_off+1e-20, relerr_comb+1e-20, "Biharmonic 2D: 8th Order Derivative Evaluation Error $(u_{recur}-u_{sympy})/u_{recur}$")
277279

278280
plt.show()

test/test_recurrence.py

Lines changed: 75 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,14 @@ def test_biharmonic2d():
139139
var = _make_sympy_vec("x", 2)
140140
var_t = _make_sympy_vec("t", 2)
141141
abs_dist = sp.sqrt((var[0]-var_t[0])**2 + (var[1]-var_t[1])**2)
142-
w = make_identity_diff_op(2)
143-
144-
partial_1x = DerivativeIdentifier((4,0), 0)
145-
partial_1y = DerivativeIdentifier((0,4), 0)
146-
biharmonic_op = {partial_1x: 1, partial_1y: 1}
142+
partial_4x = DerivativeIdentifier((4,0), 0)
143+
partial_4y = DerivativeIdentifier((0,4), 0)
144+
partial_2x2y = DerivativeIdentifier((2,2), 0)
145+
biharmonic_op = {partial_4x: 1, partial_4y: 1, partial_2x2y:2}
147146
list_pde = immutabledict(biharmonic_op)
148-
149147
biharmonic_pde = LinearPDESystemOperator(2, (list_pde,))
150-
g_x_y = abs_dist**2 * (sp.log(abs_dist)-1)
148+
149+
g_x_y = abs_dist**2 * (sp.log(abs_dist))
151150

152151
n_init, _, r = get_reindexed_and_center_origin_on_axis_recurrence(biharmonic_pde)
153152

@@ -156,15 +155,15 @@ def test_biharmonic2d():
156155
for i in range(8)]
157156

158157
x_coord = np.random.rand() # noqa: NPY002
159-
y_coord = np.random.rand() # noqa: NPY002
158+
y_coord = np.random.rand() * 1e-3 # noqa: NPY002
160159
coord_dict = {var[0]: x_coord, var[1]: y_coord}
161160
derivs = [d.subs(coord_dict) for d in derivs]
162161

163162
n = sp.symbols("n")
164163
s = sp.Function("s")
165164

166165
# pylint: disable-next=not-callable
167-
subs_dict = {s(0): derivs[0], s(1): derivs[1], s(2): derivs[1], s(3): derivs[1]}
166+
subs_dict = {s(0): derivs[0], s(1): derivs[1], s(2): derivs[2], s(3): derivs[3]}
168167
check = []
169168

170169
assert n_init == 4
@@ -175,13 +174,13 @@ def test_biharmonic2d():
175174
subs_dict[s(i)] = derivs[i]
176175

177176
f2 = sp.lambdify([var[0], var[1]], check[0])
178-
assert abs(f2(x_coord, y_coord)) <= 1e-13
177+
assert abs(f2(x_coord, y_coord)) <= 1e-11
179178
f3 = sp.lambdify([var[0], var[1]], check[1])
180-
assert abs(f3(x_coord, y_coord)) <= 1e-13
179+
assert abs(f3(x_coord, y_coord)) <= 1e-11
181180
f4 = sp.lambdify([var[0], var[1]], check[2])
182-
assert abs(f4(x_coord, y_coord)) <= 1e-13
181+
assert abs(f4(x_coord, y_coord)) <= 1e-11
183182
f5 = sp.lambdify([var[0], var[1]], check[3])
184-
assert abs(f5(x_coord, y_coord)) <= 1e-12
183+
assert abs(f5(x_coord, y_coord)) <= 1e-11
185184

186185
test_biharmonic2d()
187186

@@ -334,6 +333,69 @@ def test_helmholtz_2d_off_axis(deriv_order, exp_order):
334333
#assert relerr <= prederror
335334

336335

336+
def test_helmholtz_2d_off_axis(deriv_order, exp_order):
337+
r"""
338+
Tests off-axis recurrence code for orders up to 6 laplace2d.
339+
"""
340+
w = make_identity_diff_op(2)
341+
helmholtz2d = laplacian(w) + w
342+
343+
n = sp.symbols("n")
344+
s = sp.Function("s")
345+
346+
var = _make_sympy_vec("x", 2)
347+
var_t = _make_sympy_vec("t", 2)
348+
abs_dist = sp.sqrt((var[0]-var_t[0])**2 +
349+
(var[1]-var_t[1])**2)
350+
g_x_y = abs_dist**2*sp.log(abs_dist)
351+
derivs = [sp.diff(g_x_y,
352+
var_t[0], i).subs(var_t[0], 0).subs(var_t[1], 0)
353+
for i in range(6)]
354+
355+
x_coord = 1e-2 * np.random.rand() # noqa: NPY002
356+
y_coord = np.random.rand() # noqa: NPY002
357+
coord_dict = {var[0]: x_coord, var[1]: y_coord}
358+
start_order, recur_order, recur = get_reindexed_and_center_origin_off_axis_recurrence(helmholtz2d)
359+
360+
ic = []
361+
#Generate ic
362+
363+
for i in range(start_order):
364+
ic.append(derivs[i].subs(var[0], 0).subs(var[1], coord_dict[var[1]]))
365+
366+
n = sp.symbols("n")
367+
for i in range(start_order, 15):
368+
recur_eval = recur.subs(var[0], coord_dict[var[0]]).subs(var[1], coord_dict[var[1]]).subs(n, i)
369+
for j in range(i-recur_order, i):
370+
recur_eval = recur_eval.subs(s(j), ic[j])
371+
ic.append(recur_eval)
372+
373+
ic = np.array(ic)
374+
375+
#true_ic = np.array([derivs[i].subs(var[0], 0).subs(var[1], coord_dict[var[1]]) for i in range(15)])
376+
377+
#assert np.max(np.abs(ic[::2]-true_ic[::2])/np.abs(true_ic[::2])) < 1e-8
378+
#print(np.max(np.abs(ic[::2]-true_ic[::2])/np.abs(true_ic[::2])))
379+
380+
# CHECK ACCURACY OF EXPRESSION FOR deriv_order
381+
382+
exp, exp_range, _ = get_off_axis_expression(helmholtz2d, exp_order)
383+
approx_deriv = exp.subs(n, deriv_order)
384+
for i in range(-exp_range+deriv_order, deriv_order+1):
385+
approx_deriv = approx_deriv.subs(s(i), ic[i])
386+
387+
rat = coord_dict[var[0]]/coord_dict[var[1]]
388+
if deriv_order + exp_order % 2 == 0:
389+
prederror = abs((ic[deriv_order+exp_order+2] * coord_dict[var[0]]**(exp_order+2)/math.factorial(exp_order+2)).evalf())
390+
else:
391+
prederror = abs((ic[deriv_order+exp_order+1] * coord_dict[var[0]]**(exp_order+1)/math.factorial(exp_order+1)).evalf())
392+
print("PREDICTED ERROR: ", prederror)
393+
relerr = abs(((approx_deriv - derivs[deriv_order])/derivs[deriv_order]).subs(var[0], coord_dict[var[0]]).subs(var[1], coord_dict[var[1]]).evalf())
394+
print("RELATIVE ERROR: ", relerr)
395+
print("RATIO(x0/x1): ", rat)
396+
#assert relerr <= prederror
397+
398+
337399
def test_laplace_2d_off_axis(deriv_order, exp_order):
338400
r"""
339401
Tests off-axis recurrence code for orders up to 6 laplace2d.

test/test_recurrence_qbx.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def _qbx_lp_general(knl, sources, targets, centers, radius,
9898

9999
def _create_ellipse(n_p):
100100
h = 9.688 / n_p
101-
radius = 7*h * 1/40
101+
radius = (h * 1/4) * 1.11
102102
t = np.linspace(0, 2 * np.pi, n_p, endpoint=False)
103103

104104
unit_circle_param = np.exp(1j * t)
@@ -294,15 +294,21 @@ def _construct_laplace_axis_2d(orders, resolutions):
294294
return err
295295

296296
import matplotlib.pyplot as plt
297-
orders = [10, 16]
297+
orders = [6, 7, 8, 9]
298298
#resolutions = range(200, 800, 200)
299-
resolutions = [400, 800, 1200]
299+
resolutions = [200, 300]
300300
err_mat = _construct_laplace_axis_2d(orders, resolutions)
301301

302+
fig, ax = plt.subplots(figsize = (6, 6))
303+
ax.set_yscale("log")
304+
305+
orders_fake = [12, 14, 16, 18]
306+
302307
for i in range(len(orders)):
303-
plt.scatter(resolutions, err_mat[i], label="order QBX="+str(orders[i]))
304-
plt.xlabel("Number of Nodes")
305-
plt.ylabel("Relative Error")
306-
plt.title("2D Ellipse LP Eval Error (m=10)")
307-
plt.legend()
308+
ax.scatter(9.68845/np.array(resolutions), np.array(err_mat[i]), label="$p_{QBX}$="+str(orders_fake[i]))
309+
ax.set_xlabel("Mesh Resolution ($h$)")
310+
ax.set_ylabel("Relative Error ($L_{\infty}$)")
311+
ax.set_title("Laplace 2D: Ellipse SLP Boundary Evaluation Error $(u_{qbxrec}-u_{qbx})/u_{qbx}$")
312+
ax.legend()
308313
plt.show()
314+
#$m=100$, $r=0.28h$

0 commit comments

Comments
 (0)