{"id":40380209,"url":"https://github.com/pyamg/pyamg-examples","last_synced_at":"2026-01-20T12:01:54.933Z","repository":{"id":941950,"uuid":"10868207","full_name":"pyamg/pyamg-examples","owner":"pyamg","description":"Examples in PyAMG","archived":false,"fork":false,"pushed_at":"2024-09-06T21:24:38.000Z","size":10267,"stargazers_count":21,"open_issues_count":1,"forks_count":14,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-09-07T01:13:32.248Z","etag":null,"topics":["examples","pyamg"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pyamg.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-06-22T16:14:16.000Z","updated_at":"2024-08-16T08:29:11.000Z","dependencies_parsed_at":"2022-08-06T10:01:17.563Z","dependency_job_id":"e3b973fd-7c60-4127-ad8c-a745cc00b3f3","html_url":"https://github.com/pyamg/pyamg-examples","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pyamg/pyamg-examples","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyamg%2Fpyamg-examples","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyamg%2Fpyamg-examples/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyamg%2Fpyamg-examples/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyamg%2Fpyamg-examples/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pyamg","download_url":"https://codeload.github.com/pyamg/pyamg-examples/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pyamg%2Fpyamg-examples/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28603296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T10:46:13.255Z","status":"ssl_error","status_checked_at":"2026-01-20T10:42:51.865Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["examples","pyamg"],"created_at":"2026-01-20T12:01:54.785Z","updated_at":"2026-01-20T12:01:54.927Z","avatar_url":"https://github.com/pyamg.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"This is a collection of short examples for [PyAMG](https://github.com/pyamg/pyamg).\nThe source code for these **(and more)** examples is available at\nhttps://github.com/pyamg/pyamg-examples.\n\n### Table of Contents\n- **\u003ca href=\"#introduction\"\u003eIntroduction\u003c/a\u003e**\n  - \u003ca href=\"#overview\"\u003eOverview\u003c/a\u003e\n- **\u003ca href=\"#blackboxsolver\"\u003eBlackbox Solver\u003c/a\u003e**\n- **\u003ca href=\"#smoothedaggregationamg\"\u003eSmoothed Aggregation AMG\u003c/a\u003e**\n  - \u003ca href=\"#aggregation\"\u003eAggregation\u003c/a\u003e\n  - \u003ca href=\"#onedimensionalproblem\"\u003eOne Dimensional Problem\u003c/a\u003e\n  - \u003ca href=\"#visualizingaggregation\"\u003eVisualizing Aggregation\u003c/a\u003e\n  - \u003ca href=\"#solverdiagnostics\"\u003eSolver Diagnostics\u003c/a\u003e\n  - \u003ca href=\"#complexarithmetic\"\u003eComplex Arithmetic\u003c/a\u003e\n  - \u003ca href=\"#nonsymmetricexample\"\u003eNonsymmetric example\u003c/a\u003e\n- **\u003ca href=\"#classicalamg\"\u003eClassical AMG\u003c/a\u003e**\n  - \u003ca href=\"#coarsefinesplitting\"\u003eCoarse Fine Splitting\u003c/a\u003e\n  - \u003ca href=\"#compatiblerelaxation\"\u003eCompatible Relaxation\u003c/a\u003e\n  - \u003ca href=\"#stengthofconnection\"\u003eStength of Connection\u003c/a\u003e\n  - \u003ca href=\"#approximateidealrestriction(air)\"\u003eApproximate ideal restriction (AIR)\u003c/a\u003e\n- **\u003ca href=\"#rootnodeamg\"\u003eRootnode AMG\u003c/a\u003e**\n  - \u003ca href=\"#rootnodeamg\"\u003eRootnode AMG\u003c/a\u003e\n- **\u003ca href=\"#finiteelements\"\u003eFinite Elements\u003c/a\u003e**\n  - \u003ca href=\"#anisotropicdiffusion\"\u003eAnisotropic Diffusion\u003c/a\u003e\n  - \u003ca href=\"#linearelasticity\"\u003eLinear Elasticity\u003c/a\u003e\n- **\u003ca href=\"#preconditioning\"\u003ePreconditioning\u003c/a\u003e**\n  - \u003ca href=\"#krylovmethods\"\u003eKrylov Methods\u003c/a\u003e\n  - \u003ca href=\"#eigenvaluesolvers\"\u003eEigenvalue Solvers\u003c/a\u003e\n- **\u003ca href=\"#otherapplications\"\u003eOther Applications\u003c/a\u003e**\n  - \u003ca href=\"#graphpartitioning\"\u003eGraph Partitioning\u003c/a\u003e\n  - \u003ca href=\"#indefinitehelmholtz\"\u003eIndefinite Helmholtz\u003c/a\u003e\n  - \u003ca href=\"#high-orderdgonpoisson\"\u003eHigh-Order DG on Poisson\u003c/a\u003e\n  - \u003ca href=\"#edge-basedamg\"\u003eEdge-based AMG\u003c/a\u003e\n- **\u003ca href=\"#other\"\u003eOther\u003c/a\u003e**\n  - \u003ca href=\"#profilingperformance\"\u003eProfiling Performance\u003c/a\u003e\n\n\u003ca name=\"introduction\"\u003e\u003c/a\u003e\n### Introduction\n\n\u003ca name=\"overview\"\u003e\u003c/a\u003e\n\n#### Overview\n\n[demo.py](./0_start_here/demo.py)\n\nAs a starting example, this demo considers a rotated anisotropic\ndiffusion problem from the `pyamg.gallery`.  First, a basic\nsmoothed aggregation solver is constructed.  Then, many of the\noptions are modified to yield a more effective solver.\n\nThe comments in `demo.py` follow several steps that walk through the demo:\n\n- Step 1: import scipy and pyamg packages\n- Step 2: setup up the system using pyamg.gallery\n- Step 3: setup of the multigrid hierarchy\n- Step 4: solve the system\n- Step 5: print details\n- Step 6: change the hierarchy\n- Step 7: print details\n- Step 8: plot convergence history\n\n```\n\n\nDetails: Default AMG\n--------------------\nMultilevelSolver\nNumber of Levels:     5\nOperator Complexity:   1.125\nGrid Complexity:       1.127\nCoarse Solver:        'pinv'\n  level   unknowns     nonzeros\n     0       40000       357604 [88.91%]\n     1        4489        39601 [9.85%]\n     2         529         4489 [1.12%]\n     3          64          484 [0.12%]\n     4           9           49 [0.01%]\n\nThe residual norm is 0.2110043217253744\n\n\nThe Multigrid Hierarchy\n-----------------------\nA_0:      40000x40000        P_0:      40000x4489      \nA_1:       4489x4489         P_1:       4489x529       \nA_2:        529x529          P_2:        529x64        \nA_3:         64x64           P_3:         64x9         \nA_4:          9x9         \n\n\nDetails: Specialized AMG\n------------------------\nMultilevelSolver\nNumber of Levels:     6\nOperator Complexity:   2.159\nGrid Complexity:       1.201\nCoarse Solver:        'pinv'\n  level   unknowns     nonzeros\n     0       40000       357604 [46.31%]\n     1        6700       226352 [29.31%]\n     2        1232       176222 [22.82%]\n     3         109        11827 [1.53%]\n     4          13          169 [0.02%]\n     5           4           16 [0.00%]\n\nThe residual norm is 1.1195909450352103e-10\n\n\n```\n\n\u003cimg src=\"./0_start_here/output/amg_convergence.png\" width=\"300\"/\u003e\n\n\n***\n\n\u003ca name=\"blackboxsolver\"\u003e\u003c/a\u003e\n### Blackbox Solver\n\n[demo.py](./blackbox/demo.py)\n\nThis demo highlights using PyAMG's `blackbox` module, which attempts to solve\nan arbitrary system `A x = b` with minimal input.  The matrix `A` can be\nnon-Hermitian, indefinite, Hermitian positive-definite, etc...  The method tries\ngeneric and\nrobust settings for `smoothed_aggregation_solver(..)`.  If\n`solve()` fails to effectively solve the system,\nthen it may be helpful to look at the demo in `solver_diagonstics`\nfor guidance on automatically finding better parameter settings.\n\nTo use `solve()`, only the matrix `A` and a right-hand side `b` are needed:\n\n```python\nx = pyamg.solve(A, b, verb=True)\n```\nThe demo produces residual norms that can vary from machine to machine.\n\n```\n  Detected a Hermitian matrix\n    maxiter = 400\n    iteration 1.0\n    iteration 2.0\n    iteration 3.0\n    iteration 4.0\n    iteration 5.0\n    iteration 6.0\n    iteration 7.0\n  Residuals ||r_k||_M, ||r_0||_M = 6.45e-01, 8.68e+06\n  Residual reduction ||r_k||_M/||r_0||_M = 7.43e-08\n```\n\n***\n\n\u003ca name=\"smoothedaggregationamg\"\u003e\u003c/a\u003e\n### Smoothed Aggregation AMG\n\n\u003ca name=\"aggregation\"\u003e\u003c/a\u003e\n\n#### Aggregation\n\n[demo.py](./aggregation/demo.py)\n\nIn this example, the first-level aggregates are shown for AMG based on smoothed aggregation.\nAn example mesh and adjacency matrix is loaded from `square.mat`, followed by a call to\n`smoothed_aggregation_solver`.  Then the first-level aggregates are\nplotted. From the figure, most aggregates encompass entire groups of\nelements in the underlying mesh. Still, there are a many aggregates that yield\n\"strings\" in the aggregation, often impacting performance.\n\n\u003cimg src=\"./aggregation/output/aggregates.png\" width=\"300\"/\u003e\n\n\u003ca name=\"onedimensionalproblem\"\u003e\u003c/a\u003e\n\n#### One Dimensional Problem\n\n[demo.py](./one_dimension/demo.py)\n\nThis example illustrates the effect, in 1D, of smoothed aggregation on\ntentative prolongation operators.  Each of the aggregates (groups of three in\nthis case) are plotted with the associated (smoothed) basis functions.\n\n\u003cimg src=\"./one_dimension/output/one_dimension_aggregates.png\" width=\"300\"/\u003e\n\n\u003ca name=\"visualizingaggregation\"\u003e\u003c/a\u003e\n\n#### Visualizing Aggregation\n\n[demo1.py](./visualizing_aggregation/demo1.py)\n\n[demo2.py](./visualizing_aggregation/demo2.py)\n\nIn these two examples, the `pyamg.vis` module is called to display\naggregation in both two and three dimensions.  `demo1.py` considers the Poisson\nproblem on an unstructured triangulation of the unit square (from the PyAMG\ngallery).  In `demo2.py`, the same Poisson problem is considered on an\nunstructured tetrahedral mesh on the unit cube.  Two VTK compliant output files\nare generated in each case: `output_mesh.vtu` and `output_aggs.vtu`.\n`output_mesh.vtu` provides information on the underlying mesh (straight from\nthe unit square mesh), while `output_aggs.vtu` holds information on the\naggregates generated from first level of Smoothed Aggregation.  The process of\nvisulization in paraview is straightforward:\n\nStart [Paraview](http://www.paravieworg/paraview/resources/software.php):\n\n- open file: `output_mesh.vtu`\n  - apply\n  - under display in the object inspector: select wireframe representation\n  - under display in the object inspector: select a better solid color\n- open file: `output_aggs.vtu`\n  - apply\n  - under display in the object inspector: select surface with edges representation\n  - under display in the object inspector: select a better solid color\n  - under display in the object inspector: increase line width to see line aggregates (if present)\n  - under display in the object inspector: increase point size to see point aggregates (if present)\n\n\u003cimg src=\"./visualizing_aggregation/output/vis_aggs3.png\" width=\"300\"/\u003e\n\n\n\u003cimg src=\"./visualizing_aggregation/output/vis_aggs2.png\" width=\"300\"/\u003e\n\n\u003ca name=\"solverdiagnostics\"\u003e\u003c/a\u003e\n\n#### Solver Diagnostics\n\n[demo.py --matrix 2](./solver_diagnostics/demo.py)\n\nAMG has a range of parameter choices; selecting the optimal combination\ncan be challenging yet can lead to significant improvements in convergence.\nThis example highlights a \"solver diagnostics\" function that makes finding good parameter\nchoices a bit easier.  A brute force search is applied, and depending on the matrix\ncharacteristics (e.g., symmetry and definiteness), 60-120 different solvers are\nconstructed and then tested.  As a result, this test is intended for smaller matrix problems.\n\nThe function `solver_diagnostics` (`solver_diagnostics.py`) has many\nparameters, but the defaults should be sufficient.  For this test,\nonly the matrix, `A`, is needed, and `A` can be nonsymmetric, indefinite, or\nsymmetric positive definite.  The function detects symmetry and definiteness,\nbut it is safest to specify these.\n\nThe function outputs two separate files and we briefly examine this output\nfor the second example of rotated anisotropic diffusion when running the above\n`demo.py`. \n\nRunning\n\n```python\npython demo.py --matrix 2\n```\nwill run solver diagnostics on the rotated anisotropic diffusion problem.\n\nThe first output file is `rot_ani_diff_diagnostic.txt`, which is a sorted table\nof solver statistics for all the solvers tried.  This file has detailed output\nfor the performance of each solver, and the parameter choices used for\neach solver.\n\nThe second file defines a function `rot_ani_diff_diagnostic.py`, that when\ngiven a matrix, automatically generates and uses the best solver found.\n\n```\n\nSearching for optimal smoothed aggregation method for (2500,2500) matrix\n    ...\n    User specified a symmetric matrix\n    User specified definiteness as positive\n    ...\n    Test 1 out of 18\n    Test 2 out of 18\n    Test 3 out of 18\n    Test 4 out of 18\n    Test 5 out of 18\n    Test 6 out of 18\n    Test 7 out of 18\n    Test 8 out of 18\n    Test 9 out of 18\n    Test 10 out of 18\n    Test 11 out of 18\n    Test 12 out of 18\n    Test 13 out of 18\n    Test 14 out of 18\n    Test 15 out of 18\n    Test 16 out of 18\n    Test 17 out of 18\n    Test 18 out of 18\n    --\u003e Diagnostic Results located in rot_ani_diff_diagnostic.txt\n    --\u003e See automatically generated function definition in rot_ani_diff_diagnostic.py\n```\n\u003ca name=\"complexarithmetic\"\u003e\u003c/a\u003e\n\n#### Complex Arithmetic\n\n[demo.py --solver 1](./complex/demo.py)\n\nThe smoothed aggregation solver supports complex arithmetc and\nthere is no conversion to an equivalent real system.  For example, the\nhighlighted demo here generates a basic gauge Laplacian from quantum\nchromodynamics and solves the system for a random right-hand side and random\ninitial guess.\n   \nUsing\n```\npython demo.py --solver 1\n```\nresults in the following.\n\n```\nresidual at iteration  0: 2.00e+02\nresidual at iteration  1: 1.21e+02\nresidual at iteration  2: 2.47e+01\nresidual at iteration  3: 5.40e+00\nresidual at iteration  4: 1.46e+00\nresidual at iteration  5: 4.60e-01\nresidual at iteration  6: 1.58e-01\nresidual at iteration  7: 5.77e-02\nresidual at iteration  8: 2.20e-02\nresidual at iteration  9: 8.70e-03\nresidual at iteration 10: 3.53e-03\nresidual at iteration 11: 1.46e-03\nresidual at iteration 12: 6.12e-04\nresidual at iteration 13: 2.59e-04\nresidual at iteration 14: 1.11e-04\nresidual at iteration 15: 4.75e-05\nresidual at iteration 16: 2.04e-05\nresidual at iteration 17: 8.82e-06\nresidual at iteration 18: 3.81e-06\nresidual at iteration 19: 1.65e-06\nresidual at iteration 20: 7.13e-07\nMultilevelSolver\nNumber of Levels:     5\nOperator Complexity:   1.344\nGrid Complexity:       1.184\nCoarse Solver:        'pinv'\n  level   unknowns     nonzeros\n     0       10000        50000 [74.43%]\n     1        1658        15132 [22.53%]\n     2         170         1906 [2.84%]\n     3          12          138 [0.21%]\n     4           1            1 [0.00%]\n\n```\n\u003ca name=\"nonsymmetricexample\"\u003e\u003c/a\u003e\n\n#### Nonsymmetric example\n\n[demo.py --solver 1](./nonsymmetric/demo.py)\n\nThe smoothed aggregation solver supports nonsymmetric (i.e., non-Hermitian) and\nindefinite matrices, through recent advances in multigrid research. The\ndemo highlighted here constructs a solver for a small nonsymmetric\nrecirculating flow problem.  The out-of-the-box example diverges,\nwhile more advanced options yield a convergent solver.\n\nUsing\n\n```python\npython demo.py --solver 1\n```\n\nwe observe the following convergence history.\n\n```\n\nObserve that standard multigrid parameters for Hermitian systems\nyield a nonconvergent stand-alone solver.\n\nresidual at iteration  0: 8.64e-01\nresidual at iteration  1: 6.92e-01\nresidual at iteration  2: 2.02e+01\nresidual at iteration  3: 5.89e+02\nresidual at iteration  4: 1.72e+04\nresidual at iteration  5: 5.02e+05\nresidual at iteration  6: 1.47e+07\nresidual at iteration  7: 4.28e+08\nresidual at iteration  8: 1.25e+10\nresidual at iteration  9: 3.65e+11\nresidual at iteration 10: 1.07e+13\nresidual at iteration 11: 3.12e+14\nresidual at iteration 12: 9.10e+15\nresidual at iteration 13: 2.66e+17\nresidual at iteration 14: 7.76e+18\nresidual at iteration 15: 2.27e+20\n*************************************************************\nNow using nonsymmetric parameters for multigrid , we obtain a\nconvergent stand-alone solver. \n\nresidual at iteration  0: 8.64e-01\nresidual at iteration  1: 1.14e-01\nresidual at iteration  2: 3.53e-02\nresidual at iteration  3: 1.61e-02\nresidual at iteration  4: 8.68e-03\nresidual at iteration  5: 5.09e-03\nresidual at iteration  6: 3.08e-03\nresidual at iteration  7: 1.89e-03\nresidual at iteration  8: 1.18e-03\nresidual at iteration  9: 7.44e-04\nresidual at iteration 10: 4.78e-04\nresidual at iteration 11: 3.14e-04\nresidual at iteration 12: 2.11e-04\nresidual at iteration 13: 1.46e-04\nresidual at iteration 14: 1.04e-04\nresidual at iteration 15: 7.55e-05\n*************************************************************\nNow, we use the nonsymmetric solver to accelerate GMRES. \n\nresidual at iteration  0: 5.54e+00\nresidual at iteration  1: 1.47e+00\nresidual at iteration  2: 5.00e-01\nresidual at iteration  3: 2.96e-01\nresidual at iteration  4: 1.62e-01\nresidual at iteration  5: 5.09e-02\nresidual at iteration  6: 1.20e-02\nresidual at iteration  7: 4.86e-03\nresidual at iteration  8: 1.39e-03\nresidual at iteration  9: 9.68e-04\nresidual at iteration 10: 3.05e-04\nresidual at iteration 11: 1.36e-04\nresidual at iteration 12: 2.94e-05\nresidual at iteration 13: 6.66e-06\nresidual at iteration 14: 1.48e-06\nresidual at iteration 15: 4.32e-07\n```\n\n***\n\n\u003ca name=\"classicalamg\"\u003e\u003c/a\u003e\n### Classical AMG\n\n\u003ca name=\"coarsefinesplitting\"\u003e\u003c/a\u003e\n\n#### Coarse Fine Splitting\n\n[demo.py](./coarse_fine_splitting/demo.py)\n\nThe C/F splitting---i.e. the splitting of indices into strictly coarse nodes\n(C-pts) and strictly fine nodes (F-pts)---using Ruge-Stuben coarsening is\nillustrated in this example.  An example mesh and adjacency graph is loaded\nfrom `square.mat`, `ruge_stuben_solver()` is initiated, and the first level of\nC/F splitting is plotted.  Printing the multilevel object in this case shows that\nthe coarsening is typical: around 25% reduction in unknowns (or\ncoarsening-by-four), as shown below. The demo also plots the coarse-fine\nsplitting, with the orange C-pts and the blue F-pts.\n\n```\nMultilevelSolver\nNumber of Levels:     2\nOperator Complexity:   1.327\nGrid Complexity:       1.267\nCoarse Solver:        'pinv'\n  level   unknowns     nonzeros\n     0         191         1243 [75.33%]\n     1          51          407 [24.67%]\n\n```\n\n\u003cimg src=\"./coarse_fine_splitting/output/splitting.png\" width=\"300\"/\u003e\n\n\u003ca name=\"compatiblerelaxation\"\u003e\u003c/a\u003e\n\n#### Compatible Relaxation\n\n[demo.py](./compatible_relaxation/demo.py)\n\nThe C/F splitting---i.e. the splitting of indices into strictly coarse nodes (C-pts)\nand strictly fine nodes (F-pts)---using Compatible Relaxation is illustrated in this\nexample.  A 2d finite-difference matrix of the Poisson problem is used and the\ncoarse and fine splitting is plotted.  Coarse nodes are\nhighlighted orange, while fine nodes are highlighted blue.  In this case, the\ncoarsening is not aggressive, resulting in a coarsening-by-two.\n\n\u003cimg src=\"./compatible_relaxation/output/crsplitting.png\" width=\"300\"/\u003e\n\n\u003ca name=\"stengthofconnection\"\u003e\u003c/a\u003e\n\n#### Stength of Connection\n\n[demo.py](./strength_options/demo.py)\n\nIn this example we look at several strength of connection measures, including `symmetric`,\n`evolution`, `affinity`, and `algebraic_distance`.  From the output, we see the large impact\non convergence and the variability due to parameter selection.\n\n```\nrunning symmetric: theta=0.0\nrunning symmetric: theta=0.25\nrunning evolution: epsilon=4.0\nrunning affinity: epsilon=3.0, R=10, alpha=0.5, k=20\nrunning affinity: epsilon=4.0, R=10, alpha=0.5, k=20\nrunning algebraic_distance: epsilon=2.0, p=inf, R=10, alpha=0.5, k=20\nrunning algebraic_distance: epsilon=3.0, p=inf, R=10, alpha=0.5, k=20\n```\n\n\u003cimg src=\"./strength_options/output/strength_options.png\" width=\"300\"/\u003e\n\n\u003ca name=\"approximateidealrestriction(air)\"\u003e\u003c/a\u003e\n\n#### Approximate ideal restriction (AIR)\n\n[demo.py](./air/demo.py)\n\nWe demonstrate the use of AMG based on Approximate Ideal Restriction\n(AIR) to solve upwind discretiazations of advection. Here we consider\na simple 2d first-order upwind finite difference discretization of\nthe steady advection problem\n    $(\\cos(\\theta),\\sin(\\theta)) \\cdot \\nabla u = 0$,\nwith Dirichlet inflow BCs on the left and bottom of the domain\nenforced strongly.\n\nAIR is ideal for upwind discretizations of advection-dominated problems.\nFor pure advection, often AIR does not need Krylov acceleration; we see\nthis by converging to 1e-10 residual tolerance in as little as 7\niterations. AIR operator complexity tends to be large; here we compare\nusing AIR with distance-1 and distance-2 restriction, and with and\nwithout second pass coarsening. Distance-2 restriction and second-pass\ncoarsening will both increase operator complexity but also improve\nconvergence.\n```python\npython demo\n```\n\n```\n500 x 500 mesh:\nDistance-1 AIR using RS coarsening *without* second pass.\n\tLevels in hierarchy:        10\n\tOperator complexity:        2.604073699237941\n\tNumber of iterations:       39\n\tAverage convergence factor: 0.5452519246046812\n\nDistance-1 AIR using RS coarsening *with* second pass.\n\tLevels in hierarchy:        13\n\tOperator complexity:        3.7809599131373113\n\tNumber of iterations:       8\n\tAverage convergence factor: 0.044070522107121105\n\nDistance-2 AIR using RS coarsening *without* second pass.\n\tLevels in hierarchy:        10\n\tOperator complexity:        2.9532603668876214\n\tNumber of iterations:       11\n\tAverage convergence factor: 0.11031359469804951\n\nDistance-2 AIR using RS coarsening *with* second pass.\n\tLevels in hierarchy:        14\n\tOperator complexity:        3.77129643903191\n\tNumber of iterations:       7\n\tAverage convergence factor: 0.029339749752205272\n\n```\n\n\u003cimg src=\"./air/output/splitting.png\" width=\"300\"/\u003e\n\n\n***\n\n\u003ca name=\"rootnodeamg\"\u003e\u003c/a\u003e\n### Rootnode AMG\n\n\u003ca name=\"rootnodeamg\"\u003e\u003c/a\u003e\n\n#### Rootnode AMG\n\n[demo.py](./rootnode/demo.py)\n\nThe `rootnode_solver` is a mixture of both classical and aggregation-based\napproaches to AMG, with the intent to combine their strengths, while minimizing\ntheir respective drawbacks.  As a result, this solver is more robust for some\nproblem types, especially anisotropic diffusion.\n\nIn terms of use, the interface to `pyamg.aggregation.rootnode_solver(...)` is\nidentical to `pyamg.aggregation.smoothed_aggregation_solver(...)`, meaning that\nthe above aggregation examples can be easily changed by simply replacing calls\nto `smoothed_aggregation_solver()` with `rootnode_solver()`.\n\nThis example compares the rootnode coarsening to classical AMG's coarsening\n(see the Coarse Fine Splitting Example) and to smoothed aggregation's\ncoarsening (see the Aggregation Example).  The rootnode approach mixes\nclassical AMG and smoothed aggregation, and hence has an associated C/F\nsplitting that splits the indices into strictly coarse (C) nodes and strictly\nfine (F) nodes, and also has an associated aggregation that disjointly splits\nthe nodes into strongly connected neighborhoods.  Essentially, each aggregate\nhas one \"root\" C-node associated with it, that is injected between the fine and\ncoarse grids.\n\nAn example mesh and adjacency graph is loaded from `square.mat`, and the\n`rootnode_solver()` is initiated.  Then, the first-level C/F splitting and the\nfirst-level aggregation are plotted. Coarse nodes are highlighted orange, while\nfine nodes are highlighted blue. \n\nIn general (as well as in this example), the C/F splitting for rootnode\ncontains far fewer coarse nodes than for classical AMG.  In general, this fewer\nnumber of coarse nodes is compensated by having a somewhat denser interpolation\noperator than for classical AMG.\n\n\u003cimg src=\"./rootnode/output/rnaggs.png\" width=\"300\"/\u003e\n\n\n\u003cimg src=\"./rootnode/output/rnsplitting.png\" width=\"300\"/\u003e\n\n\n***\n\n\u003ca name=\"finiteelements\"\u003e\u003c/a\u003e\n### Finite Elements\n\n\u003ca name=\"anisotropicdiffusion\"\u003e\u003c/a\u003e\n\n#### Anisotropic Diffusion\n\n[demo.py](./diffusion/demo.py)\n\nThis demo considers different strength measures in the SA-AMG setup phase for\nfinite element (Q1) discretizations of anisotropic diffusion.  In particular,\nthe Classic Strength Measure is compared to the Evolution Measure.  For this\nexample, we see that total work is reduced by using the Evolution Measure and\nthat a scalable convergence rate is observed with rootnode:\n\n```\nRunning Grid = (100 x 100)\nRunning Grid = (200 x 200)\nRunning Grid = (300 x 300)\nRunning Grid = (400 x 400)\n\nAMG Scalability Study for Ax = 0, x_init = rand\n\nEmphasis on Robustness of Evolution Strength \nMeasure and Root-Node Solver\n\nRotated Anisotropic Diffusion in 2D\nAnisotropic Coefficient = 1.000e-03\nRotation Angle = 0.393\n    n     |    nnz    |    rho    |   OpCx    |   Work   \n--------------------------------------------------------\n Classic strength \n--------------------------------------------------------\n  10000   |   88804   |   0.86    |    1.6    |    24    \n  40000   |  357604   |   0.87    |    1.6    |    25    \n  90000   |  806404   |   0.87    |    1.6    |    27    \n 160000   |  1435204  |   0.87    |    1.6    |    27    \n--------------------------------------------------------\n Evolution strength \n--------------------------------------------------------\n  10000   |   88804   |   0.56    |    1.8    |     7    \n  40000   |  357604   |   0.67    |    1.8    |    10    \n  90000   |  806404   |   0.69    |    1.8    |    11    \n 160000   |  1435204  |   0.72    |    1.8    |    13    \n--------------------------------------------------------\n Evolution strength with Rootnode \n--------------------------------------------------------\n  10000   |   88804   |   0.46    |    1.8    |    5.4   \n  40000   |  357604   |   0.49    |    1.9    |     6    \n  90000   |  806404   |    0.5    |    1.9    |    6.3   \n 160000   |  1435204  |    0.5    |    1.9    |    6.5   \n```\n\u003ca name=\"linearelasticity\"\u003e\u003c/a\u003e\n\n#### Linear Elasticity\n\n[demo.py --solver 2](./linear_elasticity/demo.py)\n\nWe consider the 2D linear elasticity problem from the pyamg gallery in this\nexample (corresponding to a simple finite element discretization on a regular\ngrid).  Three near null space modes are fed to the\n`smoothed_aggregation_solver()` (relating to rotation and two types of\ntranslation).  Smoothed aggregation and root node are ideal for this problem\nand the results are apparent.  Very low operator complexities are observed and\nthe convergence is quick, whether you choose the root node or smoothed\naggregation solver.\n\nUsing\n\n```python\npython demo --solver 2\n```\n\nresults in the following.\n\n```\nMultilevelSolver\nNumber of Levels:     5\nOperator Complexity:   1.125\nGrid Complexity:       1.127\nCoarse Solver:        'pinv'\n  level   unknowns     nonzeros\n     0       80000      1430416 [88.91%]\n     1        8978       158404 [9.85%]\n     2        1058        17956 [1.12%]\n     3         128         1936 [0.12%]\n     4          18          196 [0.01%]\n\nNumber of iterations:  19d\n\nresidual at iteration  0: 1.63e+02\nresidual at iteration  1: 1.13e+02\nresidual at iteration  2: 8.19e+00\nresidual at iteration  3: 1.12e+00\nresidual at iteration  4: 2.57e-01\nresidual at iteration  5: 6.78e-02\nresidual at iteration  6: 1.86e-02\nresidual at iteration  7: 5.19e-03\nresidual at iteration  8: 1.46e-03\nresidual at iteration  9: 4.11e-04\nresidual at iteration 10: 1.17e-04\nresidual at iteration 11: 3.32e-05\nresidual at iteration 12: 9.52e-06\nresidual at iteration 13: 2.73e-06\nresidual at iteration 14: 7.89e-07\nresidual at iteration 15: 2.29e-07\nresidual at iteration 16: 6.65e-08\nresidual at iteration 17: 1.94e-08\nresidual at iteration 18: 5.68e-09\n```\n\n***\n\n\u003ca name=\"preconditioning\"\u003e\u003c/a\u003e\n### Preconditioning\n\n\u003ca name=\"krylovmethods\"\u003e\u003c/a\u003e\n\n#### Krylov Methods\n\n[demo.py --solver 1](./preconditioning/demo.py)\n\nThis example shows how to effectively use multilevel solvers to\nprecondition a Krylov method. The first example considers the Poisson problem\nfrom the pyamg gallery and uses a constant near-nullspace vector for SA-AMG.\nThe second example is 2D linear elasticity also from the pyamg gallery and uses\nthe typical three rigid body modes (rotation and translation in x and y) to\ncoach SA-AMG. Since both problems are symmetric and positive definite, CG\nacceleration is used. The residual histories show a clear improvement in using\nthe SA-AMG preconditioners in both cases.\n\nUsing\n\n```python\npython demo.py --solver 1\n```\n\nproduces the following.\n\n```\nMatrix: Poisson\nMultilevelSolver\nNumber of Levels:     6\nOperator Complexity:   1.337\nGrid Complexity:       1.188\nCoarse Solver:        'pinv'\n  level   unknowns     nonzeros\n     0      250000      1248000 [74.82%]\n     1       41750       373416 [22.39%]\n     2        4704        41554 [2.49%]\n     3         532         4526 [0.27%]\n     4          65          509 [0.03%]\n     5           9           65 [0.00%]\n\nMatrix: Elasticity\nMultilevelSolver\nNumber of Levels:     5\nOperator Complexity:   1.281\nGrid Complexity:       1.191\nCoarse Solver:        'pinv'\n  level   unknowns     nonzeros\n     0       80000      1430416 [78.08%]\n     1       13467       356409 [19.45%]\n     2        1587        40401 [2.21%]\n     3         192         4356 [0.24%]\n     4          27          441 [0.02%]\n\n```\n\n\u003cimg src=\"./preconditioning/output/convergence_elasticity.png\" width=\"300\"/\u003e\n\n\n\u003cimg src=\"./preconditioning/output/convergence_poisson.png\" width=\"300\"/\u003e\n\n\u003ca name=\"eigenvaluesolvers\"\u003e\u003c/a\u003e\n\n#### Eigenvalue Solvers\n\n[demo.py](./eigensolver/demo.py)\n\nIn this this example, smoothed aggregation AMG is used to precondition the\nLOBPCG eigensolver to find the lowest nine eigenmodes of a Poisson problem.\nWith preconditioning (`M=M` in the `loppcg` call), the computation of the\neigensubspace is extremely fast.\n\n\u003cimg src=\"./eigensolver/output/eigenmodes.png\" width=\"300\"/\u003e\n\n\n***\n\n\u003ca name=\"otherapplications\"\u003e\u003c/a\u003e\n### Other Applications\n\n\u003ca name=\"graphpartitioning\"\u003e\u003c/a\u003e\n\n#### Graph Partitioning\n\n[demo.py](./mesh_partition/demo.py)\n\nIn this example, we compute a partition of a basic cracked mesh (`crack_mesh.mat`)\nusing the Fiedler vector (the second lowest eigenmode of the graph laplacian).\nWe construct a SA-AMG preconditioner to assist LOBPCG in finding the Fiedler\nvector.  Positive/negative values of the Fiedler vector are plotted in\ndifferent colors, illustrating the natural splitting this mesh.\n\n\u003cimg src=\"./mesh_partition/output/mesh_partition.png\" width=\"300\"/\u003e\n\n\u003ca name=\"indefinitehelmholtz\"\u003e\u003c/a\u003e\n\n#### Indefinite Helmholtz\n\n[demo1d.py](./helmholtz/demo1d.py)\n\n[demo2d.py](./helmholtz/demo2d.py)\n\nThe example focusses on the indefinite Helmholtz wave problem.  The first\npart highlights the value in using waves to represent the near-null space, `B`.\nIn addition, we observe the waves to resemble the  (lowest) right singular vectors\nof the problem.\n\nIn the case of 2D, discontinuous Galerkin is used, yielding multiple\ndegrees of freedom at each spatial location.  As a result,\nthe fine level (level-0) aggregates of the discontinuous\nelements, largely group neighboring vertices.  The wave-like near\nnull-space is then enforced on the first coarse grid (level-1), resulting\nin four modes.\n\n```\n\nRunning 2D Helmholtz Example\n-- 10.00 Points-per-wavelength\n-- 2.73e-01 = h,  2.50 = omega\n-- Discretized with a local discontinuous Galerkin method\n   on annulus-shaped domain\nUsing only a constant mode for interpolation yields an inefficient solver.\nThis is due to aliasing oscillatory, but algebraically smooth, modes on the coarse levels.\nresidual at iteration  0: 3.14e+01\nresidual at iteration  1: 4.00e+00\nresidual at iteration  2: 2.53e+00\nresidual at iteration  3: 9.74e-01\nresidual at iteration  4: 2.76e-01\nresidual at iteration  5: 1.22e-01\nresidual at iteration  6: 5.91e-02\nresidual at iteration  7: 2.64e-02\nresidual at iteration  8: 1.48e-02\nresidual at iteration  9: 6.75e-03\nresidual at iteration 10: 3.30e-03\nresidual at iteration 11: 1.73e-03\nresidual at iteration 12: 6.48e-04\nresidual at iteration 13: 3.75e-04\nresidual at iteration 14: 1.44e-04\nresidual at iteration 15: 6.55e-05\nresidual at iteration 16: 3.85e-05\nresidual at iteration 17: 1.34e-05\nresidual at iteration 18: 7.11e-06\nresidual at iteration 19: 3.81e-06\nresidual at iteration 20: 9.36e-07\nNote the improved performance from using planewaves in B.\nresidual at iteration  0: 3.05e+01\nresidual at iteration  1: 2.62e-01\nresidual at iteration  2: 2.42e-03\nresidual at iteration  3: 2.88e-05\nresidual at iteration  4: 3.29e-07\nresidual at iteration  5: 3.87e-09\nMultilevelSolver\nNumber of Levels:     4\nOperator Complexity:   1.435\nGrid Complexity:       1.411\nCoarse Solver:        'pinv2'\n  level   unknowns     nonzeros\n     0        2880        52016 [69.67%]\n     1         880        10480 [14.04%]\n     2         256         9856 [13.20%]\n     3          48         2304 [3.09%]\n\n```\n\n\u003cimg src=\"./helmholtz/output/1dhelmholtzconv.png\" width=\"300\"/\u003e\n\n\n\u003cimg src=\"./helmholtz/output/2dhelmholtzagg.png\" width=\"300\"/\u003e\n\n\n\u003cimg src=\"./helmholtz/output/1dhelmholtzwaves.png\" width=\"300\"/\u003e\n\n\n\u003cimg src=\"./helmholtz/output/2dhelmholtzB.png\" width=\"300\"/\u003e\n\n\u003ca name=\"high-orderdgonpoisson\"\u003e\u003c/a\u003e\n\n#### High-Order DG on Poisson\n\n[demo.py](./diffusion_dg/demo.py)\n\nIn this example we look at a 2D DG discretization of a Poisson problem.\nThe mesh consists of 46 elements, with p=5, leading to 21 degrees of freedom\nper element.  The first figure shows that aggregation is local, leading to\na continuous first level.  The first coarse level (level1) candidate vector `B` is\nalso shown.\n\n```\n\nDiffusion problem discretized with p=5 and the local\ndiscontinuous Galerkin method.\nObserve that standard SA parameters for this p=5 discontinuous \nGalerkin system yield an inefficient solver.\n\nresidual at iteration  0: 2.98e+02\nresidual at iteration  1: 1.06e+01\nresidual at iteration  2: 5.08e+00\nresidual at iteration  3: 2.71e+00\nresidual at iteration  4: 1.64e+00\nresidual at iteration  5: 1.01e+00\nresidual at iteration  6: 5.20e-01\nresidual at iteration  7: 3.57e-01\nresidual at iteration  8: 2.19e-01\nresidual at iteration  9: 1.25e-01\nresidual at iteration 10: 8.53e-02\nresidual at iteration 11: 5.44e-02\nresidual at iteration 12: 3.50e-02\nresidual at iteration 13: 2.59e-02\nresidual at iteration 14: 1.79e-02\nresidual at iteration 15: 1.15e-02\nresidual at iteration 16: 6.57e-03\nresidual at iteration 17: 4.40e-03\nresidual at iteration 18: 2.49e-03\nresidual at iteration 19: 1.37e-03\nresidual at iteration 20: 8.23e-04\n\nNow use appropriate parameters, especially 'energy' prolongation\nsmoothing and a distance based strength measure on level 0.  This\nyields a much more efficient solver.\n\nresidual at iteration  0: 2.98e+02\nresidual at iteration  1: 1.32e+00\nresidual at iteration  2: 8.72e-02\nresidual at iteration  3: 1.02e-02\nresidual at iteration  4: 6.38e-04\nresidual at iteration  5: 6.65e-05\nresidual at iteration  6: 6.01e-06\nresidual at iteration  7: 6.16e-07\nresidual at iteration  8: 4.92e-08\nresidual at iteration  9: 5.41e-09\nMultilevelSolver\nNumber of Levels:     5\nOperator Complexity:   1.623\nGrid Complexity:       1.807\nCoarse Solver:        'pinv2'\n  level   unknowns     nonzeros\n     0         966        35338 [61.63%]\n     1         652        19602 [34.19%]\n     2          94         2006 [3.50%]\n     3          27          341 [0.59%]\n     4           7           49 [0.09%]\n\n```\n\n\u003cimg src=\"./diffusion_dg/output/dgaggs.png\" width=\"300\"/\u003e\n\n\n\u003cimg src=\"./diffusion_dg/output/dgmodes.png\" width=\"300\"/\u003e\n\n\u003ca name=\"edge-basedamg\"\u003e\u003c/a\u003e\n\n#### Edge-based AMG\n\n[demo.py](./edge_amg/demo.py)\n\nThis example highlights the lowest order edge AMG implementation of the\nReitzinger-Schoberl algorithm.  From the convergence figure we observe\nsignificant improvements over out-of-the-box AMG due to the use of\nthe specialized relaxation method (`hiptmair_smoother`).\n\n\u003cimg src=\"./edge_amg/output/edgeAMG_convergence.png\" width=\"300\"/\u003e\n\n\n***\n\n\u003ca name=\"other\"\u003e\u003c/a\u003e\n### Other\n\n\u003ca name=\"profilingperformance\"\u003e\u003c/a\u003e\n\n#### Scaling performance of AMG and FE assembly\n\n[demo.py](./performance/demo.py)\n\nThis demo shows the performance of finite element assembly (by way of scikit-fem)\nand multigrid setup/solve (within PCG).  The solver is run to a tolerance of `1e-8`.\nThe figure shows:\n\n- `DoFs`: the total number of degrees of freedom in the system\n- `Assembly`: the total time to assemble the FE matrix (scikit-fem)\n- `Solve prep`: the total time to condense the system to non-Dirichlet nodes (scikit-fem)\n- `Solve setup`: the total time for the AMG setup phase (pyamg)\n- `Solve`: the total time for the AMG solve phase (pyamg) withing PCG (scikit-fem)\n\n```\n|    DoFs     |  Assembly   | Solve prep  | Solve setup |    Solve    |\n|-------------|-------------|-------------|-------------|-------------|\n|           8 |     0.00169 |     0.00045 |     0.00011 |     0.00049 |\n|          27 |     0.00142 |     0.00027 |     0.00148 |     0.00054 |\n|          64 |     0.00193 |     0.00025 |     0.00210 |     0.00061 |\n|         216 |     0.00393 |     0.00025 |     0.00225 |     0.00079 |\n|         512 |     0.00760 |     0.00028 |     0.00331 |     0.00099 |\n|        1000 |     0.01450 |     0.00034 |     0.00462 |     0.00152 |\n|        2744 |     0.03646 |     0.00055 |     0.00776 |     0.00357 |\n|        5832 |     0.07144 |     0.00088 |     0.01526 |     0.00664 |\n|       12167 |     0.14817 |     0.00150 |     0.01945 |     0.01439 |\n|       27000 |     0.33348 |     0.00307 |     0.05211 |     0.03602 |\n|       54872 |     0.68135 |     0.00625 |     0.07649 |     0.07217 |\n|      110592 |     1.41124 |     0.01306 |     0.18654 |     0.16615 |\n|      238328 |     3.15382 |     0.03606 |     0.61186 |     0.40605 |\n|      474552 |     6.58809 |     0.06941 |     1.00435 |     0.86555 |\n```\n\n\u003cimg src=\"./performance/output/performance.png\" width=\"300\"/\u003e\n\n#### Profiling Performance\n\n[demo.py](./profile_pyamg/demo.py)\n\nThis is a short example on profiling the setup phase of AMG.\nHere, we use `pyinstrument` to analyze the construction of\na smoothed aggregation solver:\n\n```\n\n  _     ._   __/__   _ _  _  _ _/_   Recorded: 12:00:00  Samples:  598\n /_//_/// /_\\ / //_// / //_'/ //     Duration: 1.320     CPU time: 7.091\n/   _/                      v4.4.0\n\nProgram: demo.py --savefig\n\n\u001b[31m1.319\u001b[0m \u001b[48;5;24m\u001b[38;5;15m\u003cmodule\u003e\u001b[0m  \u001b[2mdemo.py:1\u001b[0m\n└─ \u001b[31m1.319\u001b[0m smoothed_aggregation_solver\u001b[0m  \u001b[2mpyamg/aggregation/aggregation.py:26\u001b[0m\n      [236 frames hidden]  \u001b[2mpyamg, \u003c__array_function__ internals\u003e...\u001b[0m\n         \u001b[33m0.748\u001b[0m _approximate_eigenvalues\u001b[0m  \u001b[2mpyamg/util/linalg.py:156\u001b[0m\n\n\n```\n\n***\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyamg%2Fpyamg-examples","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpyamg%2Fpyamg-examples","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpyamg%2Fpyamg-examples/lists"}