{ "cells": [ { "cell_type": "markdown", "id": "7eef65b5", "metadata": {}, "source": [ "# Darcy: thread scaling\n", "\n", "This notebook declares a Darcy discretization through the public equation API, then checks pressure and physical flux against an independently assembled conforming Q1 solution. The default control has 200 × 200 total fine cells. Complete performance campaigns remain explicit and optional.\n", "\n", "$$\n", "\\begin{aligned}\n", "-K\\nabla p&=\\boldsymbol q, &\\nabla\\cdot\\boldsymbol q&=f,\\\\\n", "K(x,y)&=\\exp\\bigl(\\sin(20\\pi x)\\sin(20\\pi y)\\bigr), &p_{\\mathrm{exact}}&=\\sin(\\pi x)\\sin(\\pi y).\n", "\\end{aligned}\n", "$$\n", "\n", "`DATA.period` controls the current material, independently derived forcing, reference and physical-flux integration. The complete timing campaign uses its fixed period-0.1 data.\n", "\n", "The domain is the unit square, with zero exterior pressure. The multiplier is the oriented normal flux. Fine Q1 pressures are conforming inside each macrocell; each macroface carries continuous piecewise P1 functions on four segments. The local kernel is the constant function. Physical volume moments select zero-mean source and trace responses.\n", "\n", "$$\n", "\\begin{aligned}\n", "A_Kp_K+B_K\\lambda&=f_K,\\\\\n", "\\sum_K B_K^{\\mathsf T}p_K&=0.\n", "\\end{aligned}\n", "$$\n", "\n", "Here $p_K$ and $\\lambda$ are coefficient vectors in the local pressure and skeletal bases; $K$ is the material coefficient. Their basis expansions define the pressure and normal flux fields.\n", "\n", "The global system retains one pressure constant per macrocell together with the multiplier. The physical flux below is the broken gradient field $-K\\nabla p_h$; the figures do not assert fine-cell H(div) conservation.\n", "\n", "The PyMHM distribution contains only the library. The first cell explicitly\n", "downloads a checksum-verified companion archive and prepares the declared data\n", "using its local Python helpers. You can inspect these support files in `ROOT`.\n", "Complete studies and historical replay retain their existing opt-in flags.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "25eb768a", "metadata": {}, "outputs": [], "source": [ "from pathlib import Path\n", "import os\n", "import sys\n", "from pymhm.io.workspace import workspace_from_archive\n", "\n", "# Download verified support files; this operation does not execute them.\n", "COMPANION_URL = \"https://ipes-lncc.github.io/pymhm/downloads/cfdd0600c19117937babd3d6ca80c9b96efa1ae23dd7eccc7f5c100d384b797a/darcy_parallel_scalability-companion.zip\"\n", "COMPANION_SHA256 = \"cfdd0600c19117937babd3d6ca80c9b96efa1ae23dd7eccc7f5c100d384b797a\"\n", "WORKSPACE = Path(\n", " os.environ.get(\"PYMHM_WORKSPACE\", Path.cwd() / \".pymhm-companions\" / COMPANION_SHA256)\n", ")\n", "ROOT = workspace_from_archive(COMPANION_URL, sha256=COMPANION_SHA256, directory=WORKSPACE)\n", "os.environ[\"PYMHM_WORKSPACE\"] = str(ROOT)\n", "if str(ROOT) not in sys.path:\n", " sys.path.insert(0, str(ROOT))\n", "\n", "# Explicitly prepare declared data with the downloaded Python helpers.\n", "from scripts.notebook_reproduction import notebook_workspace\n", "\n", "ROOT = notebook_workspace(\"introduction/darcy_parallel_scalability.ipynb\", directory=ROOT)\n", "root = ROOT\n", "print(\"Workspace:\", ROOT)\n", "\n", "\n", "import inspect\n", "import numpy as np\n", "from IPython.display import Code, display\n", "from pymhm import MeshHierarchy, bind_interface, bind_problem\n", "from pymhm.core.equations import Equation\n", "from pymhm.core.multiscale import assemble\n", "from pymhm.execution.cpu import ExecutionConfig\n", "from examples.introduction import scaling_forms as forms, scaling_threads as study\n", "\n", "DATA = forms.PeriodicDarcyData(period=0.1)\n", "RUN_CAMPAIGN = os.environ.get(\"PYMHM_RUN_CAMPAIGN\", \"0\") == \"1\"\n" ] }, { "cell_type": "markdown", "id": "267da121", "metadata": {}, "source": [ "The displayed source is the actual importable local declaration, shared by both 2D scaling notebooks. Importable providers allow the same declaration to run under threads or cross-platform spawn. To change the formulation, edit this provider or pass your own importable callable to `bind_problem`; no ready Darcy solver is called.\n", "\n", "The UFL declaration shows the weak volume and trace forms. The numerical provider uses the same public assembly operations; the native equivalence check includes all normal orientations and mean moments." ] }, { "cell_type": "code", "execution_count": null, "id": "a3743f34", "metadata": {}, "outputs": [], "source": [ "display(Code(inspect.getsource(forms.define_ufl_local_equations), language=\"python\"))\n", "display(Code(inspect.getsource(forms.LocalProvider.__call__), language=\"python\"))\n", "forms.verify_source(DATA)\n", "form_checks = study.verify_forms(DATA)\n", "print(form_checks)" ] }, { "cell_type": "markdown", "id": "e9002020", "metadata": {}, "source": [ "Build the hierarchy, bind the normal trace and declare the zero global right-hand side. Only the execution policy changes between the thread and process notebooks." ] }, { "cell_type": "code", "execution_count": null, "id": "e7a7cbd4", "metadata": {}, "outputs": [], "source": [ "macro = study.CartesianMacroMesh(10, 10)\n", "face = study.FaceSpace.uniform(1, 4, continuous=True)\n", "skeleton = study.SkeletonSpace(macro, tuple(face for _ in macro.faces))\n", "template, endpoints = forms.refined_interface_template(macro.spacing, 20, face)\n", "provider = forms.LocalProvider(\n", " macro, skeleton, template, endpoints,\n", " forms.face_length_snapshot(macro), face, refinement=20, data=DATA,\n", ")\n", "problem = bind_problem(\n", " MeshHierarchy(macro, provider.local_mesh),\n", " bind_interface(skeleton, convention=\"normal\"), provider,\n", " global_equation=Equation(0, 0), retained=1,\n", ")\n", "execution = ExecutionConfig(\n", " backend=\"thread\", workers=2, native_threads=1, batch_size=2, pipeline=True,\n", ")\n", "system = assemble(problem, execution=execution)\n", "solution = system.solve()\n", "current_mhm = macro, system, solution\n", "assert len(macro.cells) * provider.refinement**2 == 200**2\n", "print({\"fine_cells\": 200**2, \"trace_dofs\": problem.trace_size,\n", " \"retained_dofs\": len(macro.cells), \"relative_residual\": solution.residual})\n" ] }, { "cell_type": "markdown", "id": "c7f5f4aa", "metadata": {}, "source": [ "The conforming reference assembles its own Q1 volume operator and strongly eliminates zero exterior pressure. Both represented pressures and physical vector fluxes are integrated on the same partition. Macrofaces remain visible on every spatial panel." ] }, { "cell_type": "code", "execution_count": null, "id": "66cb94fb", "metadata": {}, "outputs": [], "source": [ "_, current_classical = study.run_classical(200, data=DATA)\n", "current_errors = study.show_control(current_mhm, current_classical, data=DATA)\n" ] }, { "cell_type": "markdown", "id": "db501302", "metadata": {}, "source": [ "The helper owns timing boundaries, CPU/resource checks, independent norm integration, coefficient/basis archives and plotting. Current controls are shown separately from historical measurements. Each historical record retains its original revision and machine; absent original images are reported explicitly.\n", "\n", "Set `PYMHM_RUN_CAMPAIGN=1` before execution, or call `study.run_campaign()` explicitly, to acquire the complete 200/500/1000-axis strong, weak and crossover studies. These campaigns are expensive, require the declared CPU capacity and include fresh worker startup, data transfer, synchronization, global solve and reconstruction. Their source is in [the importable scaling helpers](https://github.com/ipes-lncc/pymhm/tree/main/examples/introduction/)." ] }, { "cell_type": "code", "execution_count": null, "id": "862e0b84", "metadata": {}, "outputs": [], "source": [ "if RUN_CAMPAIGN:\n", " campaign = study.run_campaign()\n" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.12" }, "pymhm_editorial_revision": { "date": "2026-10-06", "preserved": "Code cells, execution counts, execution timestamps and numerical outputs", "preserved_code_cells_sha256": "f50e1a0ede4f576c3012650577e0491eee28608c2057a9e7cdf3f4b1b38f5b65", "scope": "Markdown citations and bibliography only" } }, "nbformat": 4, "nbformat_minor": 5 }