Add 2D boundary mode problem type and enhance waveport capabilities#657
Open
simlapointe wants to merge 68 commits intomainfrom
Open
Add 2D boundary mode problem type and enhance waveport capabilities#657simlapointe wants to merge 68 commits intomainfrom
simlapointe wants to merge 68 commits intomainfrom
Conversation
Enable Palace to accept 2D meshes and run all five solver modes (electrostatic, magnetostatic, eigenmode, driven, transient) with proper finite element discretization. Key changes: - Add L2 FE space for scalar B-field (curl E is scalar in 2D) with proper ND->L2 discrete curl operator using MFEM native assembly - Add Cross2 template for 2D cross product, dimension-aware coefficient classes for surface current and Poynting vector - Generalize BoundingBox to support 2D (mfem::Vector/DenseMatrix), handle collinear point sets, fix pointmat out-of-bounds for 2D - Add 2x2 MatrixFunction, truncate material tensors to sdim x sdim, add scalar CurlCurlInvPermeability for 2D curl-curl operator - Use ElementToEdgeTable for 2D meshes, fix GetGeomTypes for 2D - Add 3D-only guards for wave ports, Stratton-Chu, far-field - Skip curl flux error estimator for 2D (B on L2, not RT) - Add disc2d (electrostatic) and cavity2d (eigenmode) test examples with Gmsh mesh scripts and regression reference data
New example: a coplanar waveguide in top-down 2D view with two dual-element lumped ports (trace-to-ground) at each end. Uses the same dimensions as the 3D CPW (w=30 μm, s=18 μm, L=4000 μm). The trace is modeled as an internal PEC boundary (cracked mesh) with the ground planes extending to the domain boundaries. Each port has two elements connecting the trace to the top and bottom ground planes. Also fixes GetFaceVertices → GetEdgeVertices for 2D meshes in the internal boundary cracking code (AddInterfaceBdrElements).
New example mirroring the 3D CPW geometry as an x-y slice. The port patches are gap_width x gap_width squares in the gap at each end, matching the 3D CPW lumped port geometry. Port direction is along the edge (+X/-X). The trace is boolean-cut from the domain (not meshed) because in 2D a PEC region fully isolates the two gaps — there is no third dimension for the field to wrap around the trace. The trace boundary becomes PEC. Results show good CPW behavior: S11 = -15 dB at 2 GHz, half-wavelength resonance at ~18 GHz, S21 near 0 dB at low frequency. Also fixes: - Collinear bounding box: add perpendicular axis with scaled length for direction alignment checks on 1D boundaries in 2D - Relax projected length cross-check for 2D ports where the direction is perpendicular to the edge
Five new cavity2d examples testing each BC type on a rectangular 2D cavity (MFEM inline mesh, per-wall attribute control): - PMC: explicit magnetic wall on right wall, eigenfrequency shift confirms half-integer mode structure - Impedance: Rs = 1e6 Ω on right wall, finite Q from resistive loss - Absorbing: 1st-order Silver-Muller ABC, low Q from radiation loss - Conductivity: σ = 5.8e7 S/m (copper) on right wall, driven solver with lumped port excitation - Periodic: simple periodic BC (left↔right), eigenfrequencies match parallel-plate waveguide cutoffs All tests produce physically correct results and are registered in runtests.jl with reference data for regression testing.
New example: CPW cross-section (transverse-vertical plane) with sapphire substrate (ε_r=9.3) below and air above, matching the 3D CPW geometry. Electrostatic solver computes capacitance, energy distribution, surface charge, and dielectric participation ratios. Validates all 2D postprocessing features: - Domain energy: 90.38% in substrate (theory: 90.29%) - Surface flux: electric charge on trace (TwoSided=true) - Dielectric participation: SA, MS, MA interfaces with correct ordering (p_MS > p_MA, substrate-side field stronger) - All p_surf > 0, all Q_surf > 0 The mesh uses MFEM native format with explicit internal boundary elements at z=0 for the metal traces and substrate-air interface. A Gmsh-based Julia script handles geometry and meshing, then writes MFEM format directly (needed because MFEM's Gmsh reader does not import internal 1D groups for 2D meshes).
The curl flux error estimator was previously skipped for 2D because B lives on L2 (scalar), not RT (vector). This left the magnetostatic error indicator at zero and the eigenmode/driven estimator incomplete. Fix: for 2D, the curl error estimator uses H1 spaces (smooth scalar flux) and L2 (raw scalar B), with scalar MassIntegrator instead of VectorFEMassIntegrator, and a new scalar L2/H1 error qfunction. Changes: - New qfunction: l2h1_error_qf.h for scalar ||c1*u1 - c2*u2||^2 - FluxProjector: detect scalar FE spaces and use MassIntegrator - CurlFluxErrorEstimator: use scalar coefficients (1x1 mu^-1) and the scalar qfunction for 2D - TimeDependentFluxErrorEstimator: accept L2 curl space and H1 hierarchy for 2D curl estimation - All solver drivers pass L2/H1 spaces for 2D - MatrixFunction: add 1x1 matrix support for scalar sqrt/pow Verified: eigenmode indicator norm increased from 8.6e-5 (grad only) to 1.0e-4 (grad+curl). Magnetostatic indicator is now 6.5e-5 (was 0). 3D tests unchanged.
Critical fixes from code review: - C1: Fix MPI deadlock in collinear bounding box — broadcasts are now outside the dominant_rank block so all ranks participate - C2: Use z-z (out-of-plane) permeability component for 2D curl-curl, not x-x (in-plane). Added GetInvPermeabilityZZ() for coefficients - C3: Normalize eigenvectors in 2x2 MatrixFunction (divide by ||v||^2) - C4: Transient solver uses GetCurlSpace() instead of GetRTSpace() Important concerns: - I1: Removed debug print from fespace.cpp - I3: Error message prints all dimension deviations dynamically - I4: Updated stale comment about 2D curl estimator - I5: Projected length check skips only when proj_l ≈ 0, not all 2D - I6: Added magnetostatic and transient regression tests New examples: - cpw2d_square_adaptive.json: adaptive PROM frequency sweep that matches the uniform sweep with 5 solves instead of 29 (5.8x speedup) - COMSOL mesh export for cpw2d_postpro cross-section validation All existing 2D tests (7) and 3D tests (2) pass unchanged.
Two issues fixed in the COMSOL-to-Gmsh mesh converter (meshio.cpp): 1. Edge elements (edg, edg2) were silently skipped because ElemTypeComsol() had no mapping for them. Added mappings: edg to Gmsh type 1, edg2 to Gmsh type 8. 2. The geom_start offset was applied based on Gmsh type number, incorrectly shifting domain elements (tri2, quad2) that are already 1-based in COMSOL. Fixed to use element dimension: only boundary elements (dim < mesh sdim) get +1, matching COMSOL convention of 0-based boundary / 1-based domain indices.
New solver type ModeAnalysis that computes propagation modes of a 2D waveguide cross-section at a fixed frequency. Eigenvalue is the propagation constant kn, effective index n_eff = kn/k0. Validated: CPW on silicon (eps_r=11.47) gives n_eff = 2.50, matching theoretical sqrt(eps_eff) = sqrt((1+11.47)/2) = 2.497.
Phase 2 of mode analysis: add Boundaries.Postprocessing.Impedance config section for specifying voltage integration path and current loop boundaries. The solver extracts eigenvectors, computes V and I line integrals, and derives Z0, L, C. The V/I computation framework is in place but the integrals need calibration — the VectorFEBoundaryFluxLFIntegrator gives the normal flux (E.n) which may not align with the voltage direction for all gap geometries. TODO: validate against COMSOL impedance results.
…and AMR for mode analysis - Power-normalize eigenvectors to unit transmitted Poynting power so field magnitudes are physically meaningful and comparable to COMSOL. - Compute full in-plane B field Bt = -(kn/w)(z x Et) + (1/(iw))(grad Ez x z) via ProjectCoefficient onto the ND space. Output as Bt_real/Bt_imag in Paraview alongside the existing scalar Bz (Hz). - Extract both Et (ND) and En (H1) eigenvector components; pass En to PostOperator for the gradient correction in the Bt formula. - Add V/I impedance: I = integral of Bt . t dl on current boundary attributes using VectorFEBoundaryFluxLFIntegrator; Z_VI = |V|/|I|. Print both Z_PV (power-voltage) and Z_VI alongside each mode. - Add "Target" config option for ModeAnalysis solver to specify target n_eff for the eigenvalue shift-and-invert transformation. - Switch eigenvalue solver from LARGEST_REAL to LARGEST_MAGNITUDE so modes closest to the target (in absolute distance) are found on both sides. - Add TimeDependentFluxErrorEstimator for AMR support using E-field gradient flux and Bz curl flux recovery, matching the eigensolver pattern. - Call MeasureFinalize to save mesh files for GLVis visualization; handle empty ErrorIndicator gracefully in the finalization path. - Add current_marker to PostOperator; update CSV output with Z_PV/Z_VI columns.
…er class Extract the duplicated 2D boundary mode eigenvalue problem assembly and solution code from ModeAnalysisSolver and WavePortOperator into a new shared BoundaryModeSolver class. The class encapsulates: - Matrix assembly (Att, Atn, Ant, Ann, Btt) parameterized by material attribute mapping, normal projection, and loss tangent support - Block system construction with BC elimination - GMRES + sparse direct linear solver setup - SLEPc/ARPACK eigenvalue solver configuration - Shift-and-invert spectral transformation Key design: - BoundaryModeSolverConfig struct with non-owning pointers to material property data, accommodating both volume (ModeAnalysis) and boundary (WavePort) attribute mappings - Constructor assembles frequency-independent matrices on the FE space communicator (all MPI processes), configures solvers on an optional solver_comm subset (for wave port process splitting) - Solve()/SolveSplit() methods assemble frequency-dependent Att and run the eigenvalue solve, with SolveSplit handling the wave port case where only a subset of processes have solvers Net reduction: ~500 lines removed across the two callers.
…stprocessing
Add GSLIB-based line integral utility (ComputeLineIntegral) for computing
V = integral of E . dl along a straight line between two user-specified
coordinates. This provides an alternative to boundary-attribute-based
voltage integration for both mode analysis and wave port impedance.
Config: "VoltageP1", "VoltageP2" specify endpoint coordinates (in mesh
file units) for the voltage path. "IntegrationOrder" (default 100) controls
the number of Gauss-Legendre quadrature points.
Wave port postprocessing:
- Implement GetVoltage(E), GetExcitationVoltage(), and
GetCharacteristicImpedance() using the line integral on the 3D field.
- Add port-V.csv columns for wave port voltage (V_wp[port][excitation]).
- Add port-Z.csv with wave port impedance Z = V*conj(V)/(2P), where
the sign of P is corrected to ensure positive Re{Z}.
NOTE: The wave port voltage and impedance values from the GSLIB-based
line integral have not been fully validated against reference solutions.
The GSLIB point interpolation of H(curl) fields near PEC boundaries may
have reduced accuracy compared to boundary-attribute-based integration.
Users should treat these values as experimental and verify against known
results for their geometry.
…sors HIGH: - Revert GetExcitationVoltage/GetCharacteristicImpedance to TODO stubs: port_E0t lives on the 2D submesh, GSLIB cannot find 3D points on it. GetVoltage(E) using the 3D parent mesh field remains functional. MEDIUM: - ComputeLineIntegral: add byVDIM ordering detection and reorder to byNODES, matching how ProbeField handles this. - Replace unused line_length with MFEM_VERIFY for degenerate line check. - Schema: add minItems/maxItems (2-3) for VoltageP1/VoltageP2 arrays. - WavePort constructor: MFEM_VERIFY that VoltageP1 and VoltageP2 are either both provided or both omitted. - port-Z.csv: use |V|^2/(2|P|) instead of sign-flipping P, avoiding incorrect impedance for receiving ports in multi-port setups. - Fix comment "Et . n" to "Et . t (tangential)" for boundary attribute voltage integral. LOW: - Replace public has_voltage_coords with private has_voltage_coords_ and HasVoltageCoords() accessor, matching HasExcitation() pattern. - Initialize port_comm to MPI_COMM_NULL at declaration. - GetLinearSolver() returns pointer (nullable) instead of reference. - Expand Bt_inplane Piola scaling comment to explain ND-not-H(div). - Add evanescent mode normalization fallback using unit et^H Btt et when transmitted power P=0 (purely imaginary kn).
The binary (.mphbin) reader used a hardcoded element-type-based formula for geom_start that incorrectly treated 2D domain elements (triangles, quads) as boundary elements, shifting their attributes by +1. This caused "Unknown material attribute" errors when loading 2D COMSOL binary meshes. Replace with the same elem_dim < sdim logic used by the text (.mphtxt) reader, which correctly distinguishes boundary elements (dim < sdim, 0-based COMSOL entity indices needing +1) from domain elements (dim == sdim, already 1-based).
…ate-based impedance integrals
Refactor voltage and current line integrals to use multi-point paths:
- VoltagePath: list of points [[x1,y1], [x2,y2], ...] defining an open
path for V = ∫ E · dl. Replaces VoltageP1/VoltageP2. Segments are
summed: V = Σ ∫ E · dl from p_k to p_{k+1}.
- CurrentPath: list of points defining a closed polygon for the current
contour integral I = ∮ Bt · dl. The loop is automatically closed
(last point connects back to first). Uses GSLIB interpolation, avoiding
mesh edge orientation issues that affected the boundary-attribute method.
Both work via ComputeLineIntegral (GSLIB point interpolation) and are
available for mode analysis (ModeImpedanceData) and wave ports
(WavePortData).
Also filter AMR error indicators to only include propagating modes
(|Im{kn}| < 0.1 * |Re{kn}|), preventing spurious/evanescent modes from
driving refinement to irrelevant regions.
…ate horizontal New example: cpw2d_cross_section/ - Mode analysis of CPW vertical cross-section with dielectric participation - cpw2d_thick.json: finite metal thickness (100 nm PEC hole), with VoltagePath, CurrentPath, and SA/MS/MA surface loss postprocessing - cpw2d_thin.json: infinitely thin PEC at substrate surface, with VoltagePath, CurrentPath, and SA/MS/MA surface loss postprocessing - Separate Gmsh mesh scripts: mesh_thick.jl (t_metal > 0 only) and mesh_thin.jl (t_metal = 0, region-split approach for boundary control) - Validated: n_eff ~ 2.477-2.497, Z_PV ~ 38.4-38.7 Ohm, p_sub ~ 92% Consolidated: cpw2d/ (was cpw2d_square/) - Renamed cpw2d_square to cpw2d as the canonical horizontal driven example - Includes both uniform and adaptive frequency sweep configs - Keeps S-parameter comparison data Removed: cpw2d_postpro/ (electrostatic dielectric participation now covered by cpw2d_cross_section), old cpw2d/ (superseded by cpw2d_square)
The existing ModeAnalysis solver (Vardapetyan-Demkowicz formulation) uses the
divergence constraint for the H1 block, which structurally cannot capture
impedance BCs on the normal (axial) E-field. The new QuadModeAnalysis solver
derives the eigenvalue problem from the full 3D curl-curl weak form, giving a
quadratic eigenvalue problem (QEP) in lambda = ikn:
(M0 + lambda * M1 + lambda^2 * M2) [et; en] = 0
where impedance BCs enter M0 as boundary mass terms on both et and en, with no
kn-dependence. The en boundary term has opposite sign from et (from the double
cross product [n x (n x E)]_z = -En in the impedance BC).
New files:
- palace/models/quadboundarymodesolver.{hpp,cpp}: QEP solver class
- palace/drivers/quadmodeanalysissolver.{hpp,cpp}: driver for QuadModeAnalysis
- examples/cpw2d_cross_section/cpw2d_thick_{,impedance_}qep.json: test configs
Also adds a warning to the existing ModeAnalysis solver that only PEC/PMC BCs
are supported, cleans up the existing boundarymodesolver, and allows farfield
and conductivity operators in mode analysis problem types.
Add volumetric London penetration depth term (1/λ_L²)(E, F) to the QEP boundary mode solver for superconductor modeling. The London term enters as a positive mass contribution in both the ND tangential block and the H1 normal block of the M₀ operator. Includes a meshed-metal CPW example (mesh_thick_london.jl) with metal domains and a Palace config for London depth testing.
Implements a linear eigenvalue formulation (Eq 1 + Eq 2 with VD substitution
ẽn = ikn·En, et = Et) that captures both tangential and normal impedance
boundary conditions while maintaining a standard generalized eigenvalue
problem in kn². This avoids the QEP linearization doubling (N vs 2N DOFs).
The formulation uses:
A = [Att Atn] B = [Btt 0 ]
[0 Ann] [Btn 0 ]
where Ann includes H1 stiffness + mass + BC-n impedance (from Eq 2 Laplacian
IBP), and Btn = -Atn^T provides the Eq 2 coupling.
Verified against QuadModeAnalysis for PEC and Ls impedance test cases.
Problem type: "NewModeAnalysis" in the JSON config.
MaterialPropertyCoefficient locals declared inside if-blocks were destroyed before BilinearForm::FullAssemble, which dereferences the raw pointer stored by the integrator. Move coefficient declarations to the same scope as the BilinearForm so they outlive the FullAssemble call. Fixed in all three mode solvers: BoundaryModeSolver (AssembleAtt), QuadBoundaryModeSolver (M0 tt/nn imaginary), NewBoundaryModeSolver (AssembleAtt/AssembleAnn imaginary). Also switch WavePortOperator to use NewBoundaryModeSolver for wave port boundary mode computation.
Expose eigensolver error estimates (backward and absolute) in all three mode analysis solvers, matching the existing eigensolver output. Errors are printed in the log table and written to mode-kn.csv.
…q2 formulation Remove BoundaryModeSolver (Eqs 1+3, V-D sub) and QuadBoundaryModeSolver (Eqs 1+2, quadratic EVP) along with their driver classes. The remaining formulation (Eqs 1+2 with V-D substitution) supports full impedance BCs while maintaining a standard linear GEP. Rename NewBoundaryModeSolver to BoundaryModeOperator and NewModeAnalysisSolver to ModeAnalysisSolver.
When Solver.ModeAnalysis.Attributes is specified, extract a 2D boundary submesh from the 3D mesh and solve the mode analysis on it. The pipeline: - Extract ParSubMesh, remap domain/boundary attributes from parent - Collect PEC internal edges (metal traces) via global vertex matching - Gather serial mesh (PrintAsOne), restore attributes, add PEC edges - Project to 2D coordinates with material tensor rotation - Redistribute across all MPI ranks via METIS - Solve with standard 2D BoundaryModeOperator (no special-casing) Post-processing: energy density, ParaView output, CSV, GSLIB voltage/ current path integrals all work. Z_PV impedance is parallel-consistent. Also adds permittivity_imag_scalar for 2D H1 loss tangent assembly and RotateMaterialTensors for non-axis-aligned cross-sections.
Extract the ~450-line submesh pipeline from modeanalysissolver.cpp into a single reusable function ExtractStandalone2DSubmesh() in geodata.cpp. The solver's submesh block is now ~40 lines (extract + repartition + MaterialOperator). No functional changes.
The standalone 2D mesh has dim=SpaceDim=2, so RT elements and the flux error estimator work. Remove the use_submesh guard. AMR is not supported for submesh mode analysis because the 3D mesh refinement would need to be propagated to the extracted 2D mesh. Add a warning and skip the AMR loop. Also fix the AMR loop to check use_amr (previously only the mesh flattening step checked it).
Always construct SurfaceImpedanceOperator, FarfieldBoundaryOperator, and SurfaceConductivityOperator for mode analysis (remove use_submesh guard). Fix internal boundary attribute collection to include all BC types (impedance, absorbing/farfield, conductivity) — not just PEC — so that internal edges with these BCs get boundary elements in the 2D mesh. For submesh mode analysis, conductivity boundaries use their operator rather than PEC elimination (native 2D meshes retain PEC treatment for backward compatibility).
Conductivity boundaries are now handled by SurfaceConductivityOperator for both native 2D and submesh mode analysis, rather than being eliminated as PEC DOFs.
Two bugs in ExtractStandalone2DSubmesh caused segfaults with np>1: 1. PrintAsOne duplicates shared vertices without deduplication, producing disconnected mesh components. Replace with GetSerialMesh which uses H1 global TDof numbering to properly merge shared vertices and preserves real element/boundary attributes (eliminating the GatherAttrs workaround). 2. PEC edge vertex indices used per-rank local submesh numbering. After combining data from multiple ranks, local indices are meaningless. Use GetGlobalVertexIndices for globally unique submesh vertex indices that match GetSerialMesh's vertex numbering. This also fixes false dedup collisions that dropped PEC edges (e.g. 27 found instead of 30).
Implement block lower-triangular p-multigrid preconditioning for the coupled ND+H1 boundary mode eigenvalue problem. Each diagonal block uses geometric multigrid with sparse direct coarse solve: Hiptmair distributive relaxation for the ND block and Chebyshev smoothing for the H1 block. The off-diagonal shift-and-invert coupling (-sigma*Btn) is captured in the block-triangular preconditioner application. New BlockDiagonalPreconditioner class supports block-diagonal and block lower-triangular preconditioning with independent sub-solvers per block. Multigrid is disabled by default for BoundaryMode (MGMaxLevels defaults to 1); users enable it by setting MGMaxLevels > 1. PCMatShifted defaults to true when BoundaryMode multigrid is active. The coarse solver type follows the user's Type config (sparse direct, AMS, or BoomerAMG), with AMS automatically mapped to BoomerAMG for the H1 block. Wave port solves remain on sparse direct. Enable KSP timing for BoundaryMode linear solves (Preconditioner and Coarse Solve lines in the timing table).
The default is true, matching the example configs that write Paraview output.
Use the MeshPartitioner-based distribution pipeline (DistributeMesh) for the 2D submesh repartitioning instead of the direct ParMesh(comm, Mesh&, int*) constructor. The old path produced incorrect ND DOF orientations at partition boundaries, causing eigenvalues to drift as rank count increased.
RemapSubMeshBdrAttributes built the edge-to-attribute map from rank-local parent boundary elements only. An edge at the intersection of the analysis surface and an adjacent boundary could have the non-surface face on a different rank, causing the wrong attribute to be assigned. The resulting serial mesh differed depending on the 3D partitioning (np), corrupting the eigenvalue problem. Fix: use global vertex pairs and MPI_Allgatherv so every rank sees the complete edge-to-attribute picture before resolving conflicts.
Clamp the METIS partition count to min(nranks, num_elements). Ranks beyond the element count receive empty mesh partitions. This avoids a hard abort when the extracted 2D submesh has fewer elements than the total MPI rank count.
…ments" This reverts commit a411b8e.
Enable device memory for all temporary vectors in the eigenvector extraction and error estimation loop. Use MakeRef views instead of std::copy_n host iterators to extract ND/H1 subvectors from the block eigenvector, avoiding the unimplemented device-to-host path in ComplexVector::Set.
Replace std::copy_n (host-only) with mfem::forall_switch for device-aware vector sub-copies. When multigrid is enabled for boundary mode analysis, BlockDiagonalPreconditioner::Mult allocates temporary vectors with UseDevice(true), making Read()/Write() return GPU device pointers that std::copy_n cannot dereference.
blockprecond.cpp was missing from the device source list, so it was compiled by the host compiler instead of nvcc. The mfem::forall_switch lambda was not device-callable, causing the kernel to fall back to CPU execution while Read(true)/Write(true) returned device pointers.
HypreParMatrixFromBlocks requires at least one non-null block per row and column to determine sizes. When domain conductivity is the only imaginary contribution, only Atti is non-null, leaving the H1 block row and column entirely null. This produces a matrix with wrong dimensions, causing a segfault. Add zero diagonal placeholders for null block rows and columns, matching the existing Dnn pattern in BuildSystemMatrixB.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds a 2D boundary mode problem type along with multiple enhacements to waveports. Specifically:
BoundaryModesolver for mode analysis on 2D meshes, supporting both standalone 2D meshesand 2D boundary submesh extracted from a 3D mesh.
config["Boundaries"]["Postprocessing"]["Impedance"], closes Voltage and impedance postprocessing for wave ports #172.