Serial, threads and processes
Choose the execution policy after defining problem. These settings change
how local work is scheduled; the local equations, materials, moments and
interface remain the same. The API overview supplies
a complete problem definition.
Run sequentially
from pymhm import ExecutionConfig, assemble
system = assemble(problem, execution=ExecutionConfig(backend="serial"))
solution = system.solve()
The coordinator constructs, condenses and adds one macrocell before requesting the next. Use this policy for initial correctness checks and small problems.
Use independent workers
policy = ExecutionConfig(
backend="process",
workers=8,
batch_size=16,
pipeline=True,
native_threads=1,
)
system = assemble(problem, execution=policy)
solution = system.solve()
| Option | Effect |
|---|---|
backend="process" |
Independent spawned Python processes |
backend="thread" |
Threads within one process |
workers |
Maximum local workers; respect the scheduler's CPU allocation |
batch_size |
Maximum submitted work window; None uses the worker count |
pipeline=True |
Refill the ordered window as contributions are consumed |
native_threads=1 |
Limit each worker's supported BLAS/OpenMP pools |
Workers compute reduced local blocks. The coordinator adds their shared-face entries in input order; neighboring cells do not write concurrently to the global matrix. Increasing workers beyond the number of macrocells exposes no additional local parallel work.
Thread providers must keep concurrent mutable native workspaces independent. Gmsh uses process-global state and must be serialized within a process. Numba's compiled numerical kernels release the GIL, but that alone does not make every external provider thread safe.
Make process callbacks importable
Processes use spawn on every platform. Put providers, mesh factories and
coefficient callables in an importable Python module. Construct native meshes,
forms and solver resources inside the worker; return portable numerical data.
Protect the launch in a script:
from pymhm import ExecutionConfig, assemble
from my_formulation import make_problem
if __name__ == "__main__":
problem = make_problem()
system = assemble(problem, execution=ExecutionConfig(backend="process", workers=8))
solution = system.solve()
my_formulation is your module containing the mathematical definition, not a
PyMHM model module. Notebook-defined closures are suitable for serial execution;
use an importable companion module when selecting spawned workers.
Select the numerical solver independently
from pymhm import SolverConfig
system = assemble(
problem,
execution=policy,
solvers=SolverConfig(local_solver="pypardiso", global_solver="scipy"),
)
This PARDISO choice requires its installed native runtime. Mean-constrained Neumann locals are saddle systems, so an SPD-only solver cannot be selected without the appropriate projected formulation. See linear solvers.
For reusable worker resources, implement prepare_runtime() and close()
as described in execution and repeated solves.
For timing, warm the actual forms and kernels first, then include process startup,
serialization, reduction, global solution and reconstruction in the complete
clock. The Gallery contains measured parallel applications.