mom — Galerkin Method-of-Moments¶
Physical context¶
The image-charge backends (image, image_2layer, image_nlayer,
cim) all share an additional simplifying assumption: the current
distribution along an electrode is uniform per unit length.
This assumption is convenient — it lets the cluster constraints be
written directly on the per-electrode total current — but it is a
genuine approximation. The true current distribution along a thin
wire embedded in soil is non-uniform: it is concentrated at the
electrode ends and at junctions, with a residual that scales as
\(\sim 5\,\%\) of the integrated input impedance for the canonical
Sunde rod.
The Galerkin Method-of-Moments (MoM) drops this assumption. It solves a full segment-level linear system for the actual per-segment currents, and only enforces the cluster equipotentiality and sum-of-currents constraints as augmenting rows. The kernel is the same layered Green's function as the matching image backend (homogeneous for \(n = 1\), Tagg / Sunde for \(n = 2\)); only the resolution scheme differs.
mom was introduced as the second engine in ADR-0001 to provide
an independent resolution scheme against which the image
backends could be cross-validated. The agreement was deliberately
designed to be tight (within 2 %) precisely because the kernel is
identical — any larger discrepancy would point to a bug in either
the cluster constraint logic or the kernel evaluation.
Governing equation: boundary integral¶
A wire-segment system in soil satisfies the boundary integral equation
with \(G\) the layered Green's function (the same one the image backends use), \(\Sigma_j\) the surface of segment \(j\), and \(\varphi(\mathbf{r}_i)\) the (unknown) cluster potential of the cluster containing segment \(i\). In matrix form, \(Z\,I = \varphi\) with the reaction matrix
The Galerkin formulation arises by averaging \(\varphi\) over segment
\(i\) — i.e. taking the same basis function as the test function.
This is one of two natural choices; the alternative (point
matching at the segment midpoint) is implemented in
bem.
Numerical strategy¶
Reaction matrix assembly¶
The reaction matrix is built directly from the same self-kernel factory that the image backend uses:
- For
HomogeneousSoilit calls_self_corrected_kernel(seg_points, seg_lengths, wire_radii, identity, rho)— feeding the identity matrix as the "currents" argument extracts the full \(N \times N\) kernel matrix in one vectorised pass. - For
TwoLayerSoilit calls_two_layer_self_kernel_factory(soil, max_terms, tol)— same trick, but with the Tagg / Sunde geometric series.
The diagonal of \(Z\) carries the analytical line self-potential \(2 \ln(L_i / a_i) / L_i \cdot \rho_1 / (4\pi)\) plus the layered image contributions. The off-diagonals use the point-source approximation (segment midpoints) for the \(1/r + 1/r_{\text{air}}\) direct + air-mirror part and for every \(K_1^n\) image term.
Galerkin solve¶
The cluster constraints are enforced through an augmented system
with \(C\) the segment-to-cluster membership matrix (\(C_{ic} = 1\) if segment \(i\) belongs to cluster \(c\), else 0), and \(I_{c,\text{in}}\) the input current of cluster \(c\). The first \(N\) rows enforce \(\varphi_i = \varphi_c \;\forall i \in c\) on the reaction-matrix level; the next \(K\) rows enforce \(\sum_{i \in c} I_i = I_{c,\text{in}}\) for every active cluster.
The system is symmetric (since \(Z\) is symmetric and \(C\) enters
once with each sign); numpy.linalg.solve handles it directly.
Inactive segments (those whose cluster has zero input current) are excluded from the unknowns to keep the matrix small.
Real / imaginary split¶
Because \(Z\) is real and the only complex contribution to the right-hand side is the source phase, the system is solved separately for the real and imaginary part of every cluster current. This avoids complex arithmetic in the LU solve.
Validity envelope¶
| Property | Range / value |
|---|---|
| Soil model | HomogeneousSoil or TwoLayerSoil |
| Frequency | quasi-static, \(f < 1\,\text{kHz}\) |
| Electrode placement | every segment in the upper layer (for TwoLayerSoil) |
| Wire radius / segment ratio | thin-wire, \(a \ll L_i\) |
| Mesh size \(N\) | \(\le 1000\) at acceptable runtime |
For \(n \ge 3\) soils, mom does not currently apply — the
multilayer kernel is delegated to cim, mom_sommerfeld, or
bem. ADR-0002 keeps the option of extending mom with the CIM
kernel as a future action item, but the existing
mom_sommerfeld engine already covers that role.
Convergence and cost¶
- Resolution accuracy. The Galerkin scheme typically gets
within 1 % of the Dwight reference at the canonical 1.5 m / 5 mm
rod, eliminating the 4–5 % uniform-current bias of the image
backend. The improvement carries over to layered soils:
momis consistently the closest match to the literature reference values among the segment-discretised engines. - Computational cost. \(O(N^2)\) matrix build, \(O((N + K)^3)\) LU solve. For typical cases with \(N \le 1000\) the runtime is dominated by the matrix build (a few hundred milliseconds in the 2-layer case with \(\sim 200\) image terms).
- Reduction. At \(K_1 = 0\) the engine collapses bit-exactly to the homogeneous Galerkin solution.
Cross-validation notes¶
| Counterpart | Expected agreement | What is checked |
|---|---|---|
image (homogeneous) |
\(\le 2\,\%\) | uniform-current vs. Galerkin |
image_2layer (\(n = 2\)) |
\(\le 2\,\%\) | same kernel, different test function |
mom_sommerfeld (\(n = 2\)) |
\(\le 5\,\%\) | quadrature reproduces the same physics |
bem (any \(n\)) |
\(\le 5\,\%\) | Galerkin vs. collocation on the same kernel |
| Sunde / Dwight closed forms | \(\le 5\,\%\) | tighter bound than the image backend |
mom is the independent resolution-scheme reference in the
cross-validation matrix. When image and mom agree on a given
problem, the kernel is implemented correctly; when they disagree,
the disagreement is reproducible and points to a uniform-current
bias issue.
References¶
- Harrington, R. F. (1968). Field Computation by Moment Methods, Macmillan. The MoM textbook.
- Meliopoulos, A. P. S., Xia, F., Joy, E. B., Cokkinides, G. J. (1993). An advanced computer model for grounding system analysis. IEEE PWRD 8(1). MoM for grounding systems with cluster constraints.
- Sunde, E. D. (1968). Earth Conduction Effects in Transmission Systems, Dover, sect. 3.5. The line self-potential (\(2 \ln(L/a) / L\)) used on the diagonal.
- Dawalibi, F. P. & Barbeito, N. (1991). Measurements and computations of the performance of grounding systems buried in multilayer soils. IEEE PWRD 6(4). Reference values for cross-validation.
Example¶
import groundfield as gf
soil = gf.HomogeneousSoil(resistivity=100.0)
world = gf.create_world(soil=soil)
gf.create_electrode(world, "rod", name="g1",
position=(0.0, 0.0, 0.0), length=1.5)
gf.create_source(world, attached_to="g1", magnitude=1.0)
engine = gf.create_engine(backend="mom",
segment_length=0.05,
frequencies=[50.0])
result = world.solve(engine)
print(result.cluster_impedance("g1")[0])
API reference¶
mom ¶
Method-of-Moments backend (mom).
Independent second engine used to cross-validate the image backends
(see ADR-0001). The image backends approximate the current
distribution along an electrode by a uniform per unit length
profile; this backend solves for the actual non-uniform per-segment
current distribution through a Galerkin scheme.
Method
- Discretise every electrode into wire segments (same routine as the image backends).
- Assemble the full \(N \times N\) segment-level reaction matrix
\(Z\) using the same Green's-function kernel as the
corresponding image backend (so for a
HomogeneousSoilworldmomshares its physics withimage; for aTwoLayerSoilworld it shares it withimage_2layer). The diagonal of \(Z\) carries the analytical line-self-potential. - Solve the linear system $$ \begin{bmatrix} Z & -C \ C^{\top} & 0 \end{bmatrix} \begin{bmatrix} I_\text{seg} \ \varphi_c \end{bmatrix} = \begin{bmatrix} 0 \ I_\text{in} \end{bmatrix}, $$ where \(C\) is the segment-to-cluster membership matrix.
The constraint enforces equal segment potential within each
galvanic cluster; the additional row sums the segment currents to
the input current per cluster. The system is symmetric and dense;
:func:numpy.linalg.solve handles it directly.
- Compute the average cluster potential and produce a
:class:
FieldResultexactly like the image backends, so that :func:groundfield.compare_enginescan compare the two side by side.
What this means in practice
- For homogeneous soil,
momagrees withimageto within a few per cent and lies closer to the Sunde reference (the average- potential method ofimagecarries a residual ~5 % bias from the uniform-current assumption, which the Galerkin solve removes). - For 2-layer soil,
momandimage_2layeragree within the same envelope. In the limit \(\rho_2 = \rho_1\) both engines collapse onto the homogeneous solution.
Limitations
- Performance is \(O(N^3)\) for the LU solve plus \(O(N^2)\)
for the matrix build. For typical geometries
Nstays well below 1 000, so the runtime is acceptable. Larger meshes will need a preconditioned iterative solver later. - This backend deliberately re-uses the existing Green's-function kernels rather than introducing a Sommerfeld quadrature. A truly independent layered Green's function (option B in ADR-0001) would give a stronger cross-check; this lighter version is the pragmatic first step.
solve_mom ¶
solve_mom(
world: "World",
engine: "Engine",
*,
two_layer_max_terms: int | None = None,
two_layer_tol: float | None = None
) -> FieldResult
Galerkin Method-of-Moments backend.
Supports :class:HomogeneousSoil and :class:TwoLayerSoil. The
Green's-function kernel is taken from the matching image backend;
only the resolution scheme (per-segment Galerkin instead of
per-electrode average potential) differs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
world
|
'World'
|
World to evaluate. |
required |
engine
|
'Engine'
|
Engine configuration; |
required |
two_layer_max_terms
|
int | None
|
Truncation parameters for the Tagg/Sunde series, only used
when |
None
|
two_layer_tol
|
int | None
|
Truncation parameters for the Tagg/Sunde series, only used
when |
None
|
Returns:
| Type | Description |
|---|---|
FieldResult
|
Result object compatible with :class: |
Source code in src/groundfield/solver/mom.py
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 | |
Related material¶
- ADR-0001 — original methodology decision.