Newer
Older
{
"cells": [
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"from __future__ import annotations\n",
"\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import numpy.linalg as la\n",
"from pytools import add_tuples\n",
"\n",
"from sumpy.expansion.local import VolumeTaylorLocalExpansion\n",
"from sumpy.expansion.multipole import VolumeTaylorMultipoleExpansion\n",
"from sumpy.kernel import HelmholtzKernel, LaplaceKernel, YukawaKernel # noqa: F401\n",
"\n",
"if 0:\n",
" knl = LaplaceKernel(2)\n",
"else:\n",
" helm_k = 1.2\n",
" knl = HelmholtzKernel(2)\n",
" extra_kernel_kwargs = {\"k\": helm_k}\n",
" pde = [(1, (2, 0)), (1, (0, 2)), (helm_k**2, (0, 0))]\n",
"\n",
"mpole_expn = VolumeTaylorMultipoleExpansion(knl, order)\n",
"local_expn = VolumeTaylorLocalExpansion(knl, order)\n",
"\n",
"cl_ctx = cl.create_some_context(answers=[\"port\"])\n",
"\n",
"tctx = t.ToyContext(\n",
" cl_ctx,\n",
" knl,\n",
" mpole_expn_class=type(mpole_expn),\n",
" local_expn_class=type(local_expn),\n",
" extra_kernel_kwargs=extra_kernel_kwargs,\n",
")"
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"pt_src = t.PointSources(tctx, rng.uniform(-0.5, 0.5, size=(2, 50)), np.ones(50))\n",
"\n",
"mexp = t.multipole_expand(pt_src, [0, 0], order)"
]
},
{
"cell_type": "code",
"source": [
"mexp.coeffs"
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"def build_pde_mat(expn, pde):\n",
" coeff_ids = expn.get_coefficient_identifiers()\n",
" id_to_index = expn._storage_loc_dict\n",
" # FIXME: specific to scalar PDEs\n",
" pde_mat = np.zeros((len(coeff_ids), len(coeff_ids)))\n",
" row = 0\n",
" for base_coeff_id in coeff_ids:\n",
" valid = True\n",
" for pde_coeff, coeff_id_offset in pde:\n",
" other_coeff = add_tuples(base_coeff_id, coeff_id_offset)\n",
" valid = False\n",
" break\n",
" pde_mat[row, id_to_index[other_coeff]] = pde_coeff\n",
" if valid:\n",
" row += 1\n",
" else:\n",
" pde_mat[row] = 0\n",
" return pde_mat[:row]\n",
"\n",
"pde_mat = build_pde_mat(mpole_expn, pde)"
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"def find_nullspace(mat, tol=1e-10):\n",
" _u, sig, vt = la.svd(pde_mat, full_matrices=True)\n",
" zerosig = np.where(np.abs(sig) < tol)[0]\n",
" nullsp_start = zerosig[0]\n",
" assert np.array_equal(zerosig, np.arange(nullsp_start, pde_mat.shape[1]))\n",
" else:\n",
" nullsp_start = pde_mat.shape[0]\n",
" return vt[nullsp_start:].T\n",
"nullsp = find_nullspace(pde_mat)"
]
},
{
"cell_type": "code",
"source": [
"la.norm(pde_mat @ nullsp)"
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"def build_translation_mat(mexp, to_center):\n",
" n = len(mexp.coeffs)\n",
" result = np.zeros((n, n))\n",
" for j in range(n):\n",
" unit_coeffs = np.zeros(n)\n",
" unit_coeffs[j] = 1\n",
Andreas Klöckner
committed
" unit_mexp = mexp.with_coeffs(unit_coeffs)\n",
" result[:, j] = t.multipole_expand(unit_mexp, to_center).coeffs\n",
Andreas Klöckner
committed
"new_center = np.array([0, 0.5])\n",
"tmat = build_translation_mat(mexp, new_center)"
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"plt.imshow(tmat)"
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"source": [
"nullsp.shape"
]
},
{
"cell_type": "code",
"metadata": {},
Andreas Klöckner
committed
"outputs": [],
"source": [
"if 0:\n",
Andreas Klöckner
committed
" reduction_mat = nullsp.T\n",
" expansion_mat = nullsp\n",
"elif 1:\n",
" chosen_indices_and_coeff_ids = [\n",
" (i, cid)\n",
" for i, cid in enumerate(mpole_expn.get_coefficient_identifiers())\n",
" if cid[0] < 2\n",
" ]\n",
" chosen_indices = [idx for idx, _ in chosen_indices_and_coeff_ids]\n",
"\n",
" expansion_mat = np.zeros((\n",
" len(mpole_expn.get_coefficient_identifiers()),\n",
" len(chosen_indices_and_coeff_ids),\n",
" ))\n",
" for i, (idx, _) in enumerate(chosen_indices_and_coeff_ids):\n",
" expansion_mat[idx, i] = 1\n",
" reduction_mat = (nullsp @ la.inv(nullsp[chosen_indices])).T"
Andreas Klöckner
committed
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"metadata": {},
"outputs": [],
"source": [
"def plot_coeffs(expn, coeffs, **kwargs):\n",
" x = [cid[0] for cid in expn.get_coefficient_identifiers()]\n",
" y = [cid[1] for cid in expn.get_coefficient_identifiers()]\n",
" plt.scatter(x, y, c=coeffs, **kwargs)\n",
" plt.colorbar()\n",
"\n",
" for cid, coeff in zip(expn.get_coefficient_identifiers(), coeffs, strict=True):\n",
" plt.text(cid[0], cid[1] + 0.2, f\"{coeff:.1f}\")"
Andreas Klöckner
committed
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"metadata": {},
Andreas Klöckner
committed
"proj_mexp = mexp.with_coeffs(expansion_mat @ reduction_mat @ mexp.coeffs)\n",
"\n",
"proj_resid = proj_mexp.coeffs - mexp.coeffs\n",
"\n",
"plot_coeffs(mpole_expn, np.log10(1e-15 + np.abs(proj_resid)), vmin=-15, vmax=2)"
Andreas Klöckner
committed
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"metadata": {},
Andreas Klöckner
committed
"source": [
"print(t.l_inf(proj_mexp - mexp, 1.2, center=[3, 0]))"
Andreas Klöckner
committed
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"metadata": {},
Andreas Klöckner
committed
"source": [
"trans_unproj = t.multipole_expand(mexp, new_center)\n",
"trans_proj = t.multipole_expand(proj_mexp, new_center)\n",
"\n",
"print(t.l_inf(trans_unproj - trans_proj, 1.2, center=[3, 0]))"
Andreas Klöckner
committed
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"metadata": {},
Andreas Klöckner
committed
"source": [
"print(trans_proj.coeffs - trans_unproj.coeffs)"
]
},
{
"cell_type": "code",
Andreas Klöckner
committed
"metadata": {},
Andreas Klöckner
committed
"source": [
"la.norm(reduction_mat @ (trans_proj.coeffs - trans_unproj.coeffs))"
"source": [
"t.l_inf(trans_unproj - pt_src, 1.2, center=[3, 0])"
]
},
{
"cell_type": "code",
"source": [
"t.l_inf(mexp - pt_src, 1.2, center=[3, 0])"
]
}
],
"metadata": {
"kernelspec": {
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",