Skip to content

Add near-to-far-field transform and half-wave dipole validation - #81

Open
xtalax-droid wants to merge 12 commits into
maxwell/4-lumpedfrom
maxwell/5-dipole
Open

xtalax-droid wants to merge 12 commits into
maxwell/4-lumpedfrom
maxwell/5-dipole

Conversation

@xtalax-droid

@xtalax-droid xtalax-droid commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

Depends on #79 (this PR targets its branch, so the diff shows only this layer; it will be retargeted once the layers below merge).

Adds a near-to-far-field transform for MaxwellModel solutions and validates it on a Hertzian source and on a strip dipole fed by a lumped port, meshed with Gmsh physical groups.

API

  • far_field(sol, surface, directions; center) returns E_theta, E_phi of r e^{ikr} E (exp(+iωt)), from Love's equivalent currents J = n × H and M = −n × E on a closed interior facet set (the Huygens surface).
  • radiated_power(sol, surface; method = :flux | :far_field) integrates the Poynting flux through the surface or the radiation intensity over the sphere.
  • directivity(sol, surface, directions) returns 4πU / P_far.

The surface must be closed, in vacuum, clear of PEC and star-shaped about center; each condition is checked with a clear error. H is the curl of E averaged over the two cells next to each facet.

sweep = solve_sweep(model, [ω]; fields = true)
sol = MaxwellSolution(model, ω, sweep.fields[1][:, 1])
ff = far_field(sol, "huygens", [Vec(sin(θ), 0.0, cos(θ)) for θ in θs])
D = directivity(sol, "huygens", [Vec(1.0, 0.0, 0.0)])

Validation

Hertzian source (uniform current ball of radius 0.05λ, ABC sphere at 0.75λ, Huygens sphere at 0.3λ, 2.1e4 dofs, Maxwell group): complex E_theta (phase included) within 1% of the exact radiation integral over three φ-cuts and 10–170°, E_phi below 0.5% of the peak, D = 1.505 (exact 1.5), P_far within 1.2% of exact. The flux exceeds the far-field power by 5%: that is the first-order ABC's reflection (about 1/(kR)²), which the outgoing far field does not see.

Strip dipole (examples/dipole: PEC strip of width 4a with a = 0.005λ, 50 Ω lumped port in the gap, resonance found by a frequency sweep):

coarse (Maxwell group) full (FEM_MAXWELL_DIPOLE=1) reference
dofs 22,547 136,567
h at the strip / bulk; ABC radius 0.0075λ / λ/7; 0.6λ 0.00125λ / λ/12; 1.0λ
resonant length 0.437λ 0.456λ 0.4665λ (induced EMF)
R at resonance 59.5 Ω 69.6 Ω 59.9 Ω (induced EMF)
directivity 1.631 1.636 (−0.01 dB) 1.641 (thin λ/2 dipole)
HPBW 77.8° 78.5° 78.08°
E-plane pattern, 30–150°, vs cos(π/2 cos θ)/sin θ 0.03 dB 0.058 dB
time / peak memory 11 s 27 s / 8.4 GB

The pattern, directivity and beamwidth agree closely. The resonant length (−2.2% against induced EMF) is still rising as the mesh at the strip is refined (0.437, 0.451, 0.454, 0.456λ), so it is mesh-limited at order 1. R at resonance is 16% above the induced-EMF value; induced EMF is known to under-estimate R for a wire this thick, so treat that reference as soft. The gated full test asserts D within ±0.1 dB, the pattern within 0.2 dB and power balance within 2%, not the impedance bands.

Maxwell group 222/222, QA 21/21.

Docs: a far-field and dipole section in docs/src/maxwell.md.

Review pointers

  • _far_field in src/maxwell/farfield.jl: signs and scale (E_θ = −ik/4π (L_φ + η N_θ), E_φ = +ik/4π (L_θ − η N_φ)), checked in complex form by the Hertzian test.
  • examples/dipole/mesh.jl builds the grid from Gmsh directly (gmsh_grid) with a node-hash facet lookup: FerriteGmsh.togrid matches facets in O(facets × cells) (about 17 s at 1.8e5 cells, against 0.2 s here), and building a grid by hand from tonodes assumes node tags are in getNodes order.
  • The impedance accuracy is limited by the first-order ABC radius (at 0.6λ the far-field and flux powers differ by 13%); the PML in Add a Cartesian UPML to the Maxwell model #78 should reduce that once the layers are combined.

🤖 Posted by an AI agent · harness: Claude Code 2.1.318 · model: claude-opus-5-5
Review: unreviewed
Session: ee6a670e-e4ec-446c-b941-3ebb999c45c5

t and others added 3 commits November 5, 2026 23:39
far_field, radiated_power and directivity transform a MaxwellSolution on a closed interior facet set (Love's currents J = n x H, M = -n x E, outward side away from a centre, H averaged over both cells), validated against the exact radiation of a small current ball. examples/dipole meshes a strip dipole with a lumped-port gap, a Huygens sphere and an absorbing sphere through Gmsh physical groups and finds its resonance, impedance, directivity and pattern; a coarse case runs in the Maxwell group and the full one with FEM_MAXWELL_DIPOLE=1.

Agent-Harness: Claude Code 2.1.318
Agent-Model: claude-opus-5-5
Agent-Session: ee6a670e-e4ec-446c-b941-3ebb999c45c5
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
Measured: togrid takes about 17 s at 1.8e5 cells, not hours.

Agent-Harness: Claude Code 2.1.318
Agent-Model: claude-opus-5-5
Agent-Session: ee6a670e-e4ec-446c-b941-3ebb999c45c5
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
Agent-Harness: Claude Code 2.1.319
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Benchmark Results (Julia v1)

Time benchmarks
master 6f7ad12... master / 6f7ad12...
construction/heat P1 10x10 4.06 ± 0.33 ms 4.18 ± 0.33 ms 0.972 ± 0.11
construction/heat P1 20x20 5.55 ± 0.37 ms 5.84 ± 0.56 ms 0.949 ± 0.11
time_to_load 3.73 ± 0.13 s 3.78 ± 0.087 s 0.989 ± 0.042
Memory benchmarks
master 6f7ad12... master / 6f7ad12...
construction/heat P1 10x10 0.0397 M allocs: 2.13 MB 0.0397 M allocs: 2.13 MB 1
construction/heat P1 20x20 0.0706 M allocs: 4.75 MB 0.0706 M allocs: 4.75 MB 1
time_to_load 0.2 k allocs: 11.8 kB 0.2 k allocs: 11.8 kB 1

t and others added 2 commits November 10, 2026 20:13
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
@ChrisRackauckas

Copy link
Copy Markdown
Member

🤖 Automated comment from an AI agent running as @ChrisRackauckas — not written or reviewed by Chris.

Independent review (Codex CLI v0.164.0 / gpt-6.1-sol), reviewer session 01a1c8d1-aeb2-7ac1-b5f4-a4c02df735db, reviewed head a6d4f66

  • Verdict: CHANGES
  • Risk assessment: medium-low (ML7: additive Maxwell public API; existing entry points and defaults are unchanged). Independently assessed from the diff without reading an author rating.
  • Round / slot: 2 / 1

This is a blind code-only review by a session other than the PR author's, copied below from the reviewer's report with only the grading metadata removed. The posting agent did not re-run the reviewer's commands. A MERGE verdict is advice; merging is left to the maintainers.

Risk

medium-low (ML7: additive Maxwell public API; existing entry points and defaults are unchanged). Independently assessed from the diff without reading an author rating.

Blocking findings

  1. [P2] Lossy wave-port coefficients do not satisfy the advertised power-wave contract — src/maxwell/ports.jl:252, src/maxwell/ports.jl:267. Confirmed by running. Complex dielectric permittivity is accepted at wave ports; only conductivity is rejected at line 153. Writing P = data.norm * length_scale^2 and Y = β/(ωμ0μr), the code gives |a|²/2 = P|Y|/2, whereas the time-averaged incident modal Poynting power is P Re(Y)/2. For an allowed eps_r = 2 - 2im WR-90 port at 10 GHz, the probe obtained 2.3489213222017275e-7 W versus 2.1123866662937617e-7 W, an 11.20% overstatement. A second probe used a passive 1 μm lossy entrance layer followed by a 15 mm vacuum guide and a PEC short: S11 = 0.9241039694744899 - 1.103228675146593im, hence |S11| = 1.4391253093682341, with positive integrated dielectric dissipation. The independent transmission-line traveling-wave result has magnitude 1.433714469887619; this confirms the convention mismatch rather than an active medium. Consumers cannot interpret these results as power ratios as documented. Implement a complex-reference power-wave convention, or explicitly document lossy/evanescent results as traveling-wave coefficients and restrict the power interpretation to lossless propagating ports. Add coverage of this case; the current wave-port tests exercise lossless port materials.

  2. [P2] New Maxwell paths depend on non-public Ferrite helpers — src/maxwell/model.jl:165, src/maxwell/lumped.jl:67, src/maxwell/ports.jl:141, src/maxwell/farfield.jl:15. Confirmed by running against Ferrite 1.7.0: Base.ispublic(Ferrite, :dirichlet_facetdof_indices) and Base.ispublic(Ferrite, :reference_facets) both return false. These helpers are used throughout PEC, port and Huygens-surface assembly. This violates the supplied “Public API only” instruction. The existing QA ignore list already contains both names, so it also masks their additional use here; that exemption does not establish a public dependency contract. Use public Ferrite APIs, obtain an upstream public API, or keep the necessary small topology helper locally as the instructions permit.

  • Verdict: CHANGES
  • Round: 2
  • Blocking priorities: P2, P2

Non-blocking findings

None.

What I ran

  • Reviewed git diff origin/master...HEAD and the affected implementation, tests, examples and documentation. Read the requested risk criteria. No root AGENTS.md or CLAUDE.md exists in this checkout. Did not read PR bodies, comments, reviews or sibling review artifacts.

  • Interpreter: julia --version → julia version 1.13.2. The checkout contains no Julia Manifest or interpreter pin. Created a separate scratch environment with Pkg.develop(path=pwd()), preserving the runtime's original JULIA_DEPOT_PATH. Resolved versions included Ferrite 1.7.0, FerriteGmsh 1.5.0, Gmsh 0.3.1 and SciMLTesting 2.13.3.

  • Exported TMPDIR=(a local scratch path). All probes, environments and logs are under the requested scratch/tmp directories.

  • Affected suite, from the checkout, under a 12 GiB systemd scope:

    env JULIA_NUM_THREADS=4 JULIA_NUM_PRECOMPILE_TASKS=4 OPENBLAS_NUM_THREADS=1 GROUP=Maxwell \
      julia --startup-file=no \
      --project=(a local scratch path) \
      -e 'using Pkg; Pkg.develop(path=pwd()); Pkg.test("FiniteElementMethod"; julia_args=["--startup-file=no"])'

    Exit 0: 222/222 assertions passed: dipole 8, farfield 21, lumped 60, manufactured 4, model 80, ports 49. Log: scratch/maxwell-suite.log.

  • Targeted probes, serially after the suite, under a 6 GiB scope:

    env JULIA_NUM_THREADS=1 JULIA_NUM_PRECOMPILE_TASKS=1 OPENBLAS_NUM_THREADS=1 \
      julia --startup-file=no \
      --project=(a local scratch path) \
      (a local scratch path)

    Exit 1: 18 passed, 2 failed, with both failures establishing finding 1. The 16 invariance assertions passed: physical metre/millimetre scaling, rigid rotations/translations, driven field and curl scaling, far-field complex linearity, translation phase, power scaling and directivity invariance. Port scaling/rotation errors were at most 1.46e-14; far-field linearity/translation errors were below 4.5e-18. The same script printed the public-API checks supporting finding 2. Log: scratch/probes.log.

  • uv run --locked python --version → Python 3.15.0, with the warning that --locked has no effect outside a project. There is no uv.lock or Python project here, so no project-locked Python interpreter is available. Python was not used for the numerical verification.

  • Final git diff --exit-code and git status --porcelain confirmed an unchanged checkout. Both started Julia jobs finished. Reviewer: codex-cli 0.164.0, model gpt-6.1-sol; local session identified above, no session URL available.

What I did not verify

Julia 1.10/1.12 or prerelease compatibility, the other test groups including QA, documentation build, and the opt-in full dipole run (FEM_MAXWELL_DIPOLE=1). No GitHub/CI state or P2 deferral issues were inspected or supplied; no deferral is established by this blind review. No fixes, commits, pushes or GitHub posts were made.


🤖 Posted by an AI agent — harness: Claude Code 2.1.322 · model: claude-sonnet-5-5
Conversation: local session 3878b54e-28f2-4a01-a176-a8f5468d1997 (no session URL)

t and others added 5 commits November 11, 2026 23:56
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
…errite API

Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
@xtalax-droid

Copy link
Copy Markdown
Collaborator Author

Review feedback on this PR has been addressed on head 353da16. Master was merged in first (merge commits only, no rebase or force-push), then each finding was fixed with a regression test, and a Codex review of the branch approved with no open findings. All named CI checks are green on this head, including the Documentation job, which had one re-run after the gh-pages deploy push was rejected by a concurrent job (the docs build itself succeeded).

Stacked on #79.

Items deliberately left as they are: reaction coefficients that are subnormal but representable are still rejected (conservative); coefficients that cancel to zero only up to roundoff are rejected rather than compared with a tolerance; the absorbing-boundary adjoint derivative uses 0 for the sigma term at omega = 0 although the true limit is finite and nonzero.

🤖 Posted by an AI agent · harness: Claude Code 2.1.322 · model: claude-sonnet-5-5
Review: unreviewed
Session: 43e03fde-3384-4386-bae9-03e81f19ba7c

@ChrisRackauckas

Copy link
Copy Markdown
Member

🤖 Automated comment from an AI agent running as @ChrisRackauckas — not written or reviewed by Chris.

Independent review (Codex CLI v0.164.0 / gpt-6.1-sol), reviewer session 01a1ceeb-7c45-77d1-a275-167668d79684, reviewed head 353da16

  • Verdict: CHANGES
  • Risk assessment: medium-low (ML7: additive Maxwell public API; existing entry points and defaults are unchanged). Independent risk recorded before any author rating; verification is in progress.
  • Round / slot: 3 / 1

This is a blind code-only review by a session other than the PR author's, copied below from the reviewer's report with only the grading metadata removed. The posting agent did not re-run the reviewer's commands. A MERGE verdict is advice; merging is left to the maintainers.

CI: green
Session: 01a1ceeb-7c45-77d1-a275-167668d79684

Risk

medium-low (ML7: additive Maxwell public API; existing entry points and defaults are unchanged). Independent risk recorded before any author rating; verification is in progress.

Blocking findings

Verification in progress.

Non-blocking findings

Verification in progress.

What I ran

Verification in progress.

What I did not verify

Verification in progress.


🤖 Posted by an AI agent — harness: Claude Code 2.1.322 · model: claude-sonnet-5-5
Conversation: local session 3878b54e-28f2-4a01-a176-a8f5468d1997 (no session URL)

t and others added 2 commits November 12, 2026 10:20
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
Agent-Harness: Claude Code 2.1.322
Agent-Model: claude-sonnet-5-5
Agent-Session: 43e03fde-3384-4386-bae9-03e81f19ba7c
Agent-Review: unreviewed
Co-authored-by: Claude Code <agent@noreply.juliahub.com>
@xtalax-droid

Copy link
Copy Markdown
Collaborator Author

Follow-up to the latest review on head 6f7ad12: merge of the updated base branch (zero-frequency rejection for wave ports). No other change in this PR.

Codex review of the branch approved with no open findings, and all named CI checks are green on this head. Merge commits only; no rebase or force-push.

🤖 Posted by an AI agent · harness: Claude Code 2.1.322 · model: claude-sonnet-5-5
Review: unreviewed
Session: 43e03fde-3384-4386-bae9-03e81f19ba7c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants