From b82cca5de8029e90583f55fe16ac78f5eaa8a4f2 Mon Sep 17 00:00:00 2001 From: Hugh Carson Date: Mon, 6 Jan 2025 14:12:10 -0500 Subject: [PATCH 1/6] Use variadic method to remove method --- palace/utils/tablecsv.hpp | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/palace/utils/tablecsv.hpp b/palace/utils/tablecsv.hpp index 874f80549..f99bd3df3 100644 --- a/palace/utils/tablecsv.hpp +++ b/palace/utils/tablecsv.hpp @@ -47,7 +47,7 @@ class Column // Normal float in our exponent format needs float_precision + 7 ("+" , leading digit, // ".", "e", "+", +2 exponent. Sometimes exponent maybe +3 if very small or large; see - // std::numeric_limits::max_exponent. We pick +7 for consistnacy, but + // std::numeric_limits::max_exponent. We pick +7 for consistency, but // min_left_padding should be at least 1, which is not currently enforced. return std::max(pad + prec + 7, header_text.size()); } @@ -142,23 +142,6 @@ class Table } // Insert columns: map like interface - - bool insert_column(std::string column_name, std::string column_header = "") - { - auto it = std::find_if(cols.begin(), cols.end(), - [&column_name](auto &c) { return c.name == column_name; }); - if (it != cols.end()) - { - return false; - } - auto &col = cols.emplace_back(std::move(column_name), std::move(column_header)); - col.defaults = &col_options; - if (reserve_n_rows > 0) - { - col.data.reserve(reserve_n_rows); - } - return true; - } bool insert_column(Column &&column) { auto it = std::find_if(cols.begin(), cols.end(), @@ -175,6 +158,11 @@ class Table } return true; } + template + bool insert_column(Args &&...args) + { + return insert_column(Column(std::forward(args)...)); + } // Access columns via vector position or column name From ddd749dea4126599b5b18e1b3dd7fad06a1f8b60 Mon Sep 17 00:00:00 2001 From: Hugh Carson Date: Mon, 6 Jan 2025 14:16:29 -0500 Subject: [PATCH 2/6] Simplify PostOperator to remove mutability of cache and optional --- palace/drivers/basesolver.cpp | 3 +- palace/drivers/drivensolver.cpp | 8 +- palace/drivers/drivensolver.hpp | 2 +- palace/drivers/eigensolver.cpp | 7 +- palace/drivers/transientsolver.cpp | 2 +- palace/models/postoperator.cpp | 571 ++++++++++------------------- palace/models/postoperator.hpp | 80 ++-- 7 files changed, 253 insertions(+), 420 deletions(-) diff --git a/palace/drivers/basesolver.cpp b/palace/drivers/basesolver.cpp index 08bf90c28..db505f8f4 100644 --- a/palace/drivers/basesolver.cpp +++ b/palace/drivers/basesolver.cpp @@ -15,7 +15,6 @@ #include "linalg/ksp.hpp" #include "models/domainpostoperator.hpp" #include "models/postoperator.hpp" -#include "models/spaceoperator.hpp" #include "models/surfacepostoperator.hpp" #include "utils/communication.hpp" #include "utils/dorfler.hpp" @@ -497,7 +496,7 @@ void BaseSolver::SurfacesPostPrinter::AddMeasurementEps(double idx_value_dimensi using fmt::format; // Interface Participation adds energy contriutions E_elec + E_cap - // E_cap returns zero if the solver does not supprot lumped ports. + // E_cap returns zero if the solver does not support lumped ports. double E_elec = post_op.GetEFieldEnergy() + post_op.GetLumpedCapacitorEnergy(); auto eps_data_vec = post_op.GetInterfaceEFieldEnergyAll(); diff --git a/palace/drivers/drivensolver.cpp b/palace/drivers/drivensolver.cpp index b015ba734..3725b5c7f 100644 --- a/palace/drivers/drivensolver.cpp +++ b/palace/drivers/drivensolver.cpp @@ -188,7 +188,7 @@ ErrorIndicator DrivenSolver::SweepUniform(SpaceOperator &space_op, PostOperator post_op.SetEGridFunction(E); post_op.SetBGridFunction(B); post_op.SetFrequency(omega); - post_op.MeasureAll(); + post_op.MeasureAll(space_op); Mpi::Print(" Sol. ||E|| = {:.6e} (||RHS|| = {:.6e})\n", linalg::Norml2(space_op.GetComm(), E), @@ -367,7 +367,7 @@ ErrorIndicator DrivenSolver::SweepAdaptive(SpaceOperator &space_op, PostOperator post_op.SetEGridFunction(E); post_op.SetBGridFunction(B); post_op.SetFrequency(omega); - post_op.MeasureAll(); + post_op.MeasureAll(space_op); Mpi::Print(" Sol. ||E|| = {:.6e}\n", linalg::Norml2(space_op.GetComm(), E)); @@ -617,7 +617,9 @@ void DrivenSolver::SParametersPostPrinter::AddMeasurement( for (const auto o_idx : all_port_indices) { - std::complex S_ij = post_op.GetSParameter(src_lumped_port, o_idx, source_idx); + std::complex S_ij = + src_lumped_port ? post_op.GetSParameter(lumped_port_op, o_idx, source_idx) + : post_op.GetSParameter(wave_port_op, o_idx, source_idx); auto abs_S_ij = 20.0 * std::log10(std::abs(S_ij)); auto arg_S_ij = std::arg(S_ij) * 180.0 / M_PI; diff --git a/palace/drivers/drivensolver.hpp b/palace/drivers/drivensolver.hpp index 4fd3ab9bf..d51bc1230 100644 --- a/palace/drivers/drivensolver.hpp +++ b/palace/drivers/drivensolver.hpp @@ -70,7 +70,7 @@ class DrivenSolver : public BaseSolver bool do_measurement_ = false; TableWithCSVFile port_S; - // Currently can't mix lumped and sufrace ports for s-matrix + // Currently can't mix lumped and surface ports for s-matrix bool src_lumped_port = true; int source_idx = -1; diff --git a/palace/drivers/eigensolver.cpp b/palace/drivers/eigensolver.cpp index b050790fb..80f3761dc 100644 --- a/palace/drivers/eigensolver.cpp +++ b/palace/drivers/eigensolver.cpp @@ -316,7 +316,7 @@ EigenSolver::Solve(const std::vector> &mesh) const post_op.SetEGridFunction(E); post_op.SetBGridFunction(B); post_op.SetFrequency(omega); - post_op.MeasureAll(); + post_op.MeasureAll(space_op); const double E_elec = post_op.GetEFieldEnergy(); const double E_mag = post_op.GetHFieldEnergy(); @@ -591,7 +591,8 @@ void EigenSolver::EPRPostPrinter::AddMeasurementEPR( port_EPR.table["idx"] << eigen_print_idx; for (const auto idx : ports_with_L) { - port_EPR.table[format("p_{}", idx)] << post_op.GetInductorParticipation(idx, E_m); + port_EPR.table[format("p_{}", idx)] + << post_op.GetInductorParticipation(lumped_port_op, idx, E_m); } port_EPR.AppendRow(); } @@ -616,7 +617,7 @@ void EigenSolver::EPRPostPrinter::AddMeasurementQ(double eigen_print_idx, port_EPR.table["idx"] << eigen_print_idx; for (const auto idx : ports_with_R) { - double Kl = post_op.GetExternalKappa(idx, E_m); + double Kl = post_op.GetExternalKappa(lumped_port_op, idx, E_m); double Ql = (Kl == 0.0) ? mfem::infinity() : omega.real() / std::abs(Kl); port_Q.table[format("Ql_{}", idx)] << Ql; diff --git a/palace/drivers/transientsolver.cpp b/palace/drivers/transientsolver.cpp index aafbba48b..b1f15d2de 100644 --- a/palace/drivers/transientsolver.cpp +++ b/palace/drivers/transientsolver.cpp @@ -109,7 +109,7 @@ TransientSolver::Solve(const std::vector> &mesh) const const Vector &B = time_op.GetB(); post_op.SetEGridFunction(E); post_op.SetBGridFunction(B); - post_op.MeasureAll(); + post_op.MeasureAll(space_op); const double E_elec = post_op.GetEFieldEnergy(); const double E_mag = post_op.GetHFieldEnergy(); diff --git a/palace/models/postoperator.cpp b/palace/models/postoperator.cpp index 8b42e42e6..b889adf6b 100644 --- a/palace/models/postoperator.cpp +++ b/palace/models/postoperator.cpp @@ -38,8 +38,7 @@ PostOperator::PostOperator(const IoData &iodata, SpaceOperator &space_op, surf_post_op(iodata, space_op.GetMaterialOp(), space_op.GetH1Space()), dom_post_op(iodata, space_op.GetMaterialOp(), space_op.GetNDSpace(), space_op.GetRTSpace()), - interp_op(iodata, space_op.GetNDSpace()), lumped_port_op(&(space_op.GetLumpedPortOp())), - wave_port_op(&(space_op.GetWavePortOp())), + interp_op(iodata, space_op.GetNDSpace()), E(std::make_unique(space_op.GetNDSpace(), iodata.problem.type != config::ProblemData::Type::TRANSIENT)), @@ -347,260 +346,158 @@ void PostOperator::SetAGridFunction(const Vector &a, bool exchange_face_nbr_data void PostOperator::ClearAllMeasurementCache() { // Clear Cache: Save omega since this set by hand like fields E,... - bool has_omega = measurment_cache.omega.has_value(); - std::complex omega; - if (has_omega) - { - omega = *measurment_cache.omega; - } - - measurment_cache = {}; - - if (has_omega) - { - measurment_cache.omega = omega; - } + auto omega = measurement_cache.omega; + measurement_cache = {}; + measurement_cache.omega = omega; } void PostOperator::MeasureAll() { ClearAllMeasurementCache(); - // Domain Energy: Electric Field Contribution - if (V || E) - { - GetEFieldEnergy(); // if (dom_post_op.M_elec) - if (dom_post_op.M_i.size() > 0) - { - GetEFieldEnergy(dom_post_op.M_i.begin()->first); // Measures all domains - } - } - // Domain Energy: Magnetic Field Contribution - if (A || B) - { - GetHFieldEnergy(); // if (dom_post_op.M_mag) - if (dom_post_op.M_i.size() > 0) - { - GetHFieldEnergy(dom_post_op.M_i.begin()->first); // Measures all domains - } - } + MeasureEFieldEnergy(); + MeasureHFieldEnergy(); - if (E || B) - { - GetSurfaceFluxAll(); - } - if (E) - { - GetInterfaceEFieldEnergyAll(); - ProbeEField(); - } - if (B) - { - ProbeBField(); - } - if (E && B) - { - if (lumped_port_op != nullptr) - { - MeasureLumpedPorts(); - } - if (wave_port_op != nullptr) - { - MeasureWavePorts(); - } - } + MeasureSurfaceFlux(); + MeasureInterfaceEFieldEnergy(); + MeasureProbes(); +} + +void PostOperator::MeasureAll(const SpaceOperator &space_op) +{ + MeasureAll(); + MeasureLumpedPorts(space_op.GetLumpedPortOp()); + MeasureWavePorts(space_op.GetWavePortOp()); } void PostOperator::SetFrequency(double omega) { - measurment_cache.omega = std::complex(omega); + measurement_cache.omega = std::complex(omega); } void PostOperator::SetFrequency(std::complex omega) { - measurment_cache.omega = omega; + measurement_cache.omega = omega; } std::complex PostOperator::GetFrequency() const { - MFEM_VERIFY(measurment_cache.omega.has_value(), - "Frequency value omega has not been correctly set!"); - return *measurment_cache.omega; + return measurement_cache.omega; } double PostOperator::GetEFieldEnergy() const { - if (!measurment_cache.domain_E_field_energy_all.has_value()) - { - if (V) - { - measurment_cache.domain_E_field_energy_all = dom_post_op.GetElectricFieldEnergy(*V); - } - else if (E) - { - measurment_cache.domain_E_field_energy_all = dom_post_op.GetElectricFieldEnergy(*E); - } - else - { - // No failure: returns zero - measurment_cache.domain_E_field_energy_all = 0.0; - } - } - return *measurment_cache.domain_E_field_energy_all; + return measurement_cache.domain_E_field_energy_all; } -double PostOperator::GetHFieldEnergy() const +double PostOperator::GetEFieldEnergy(int idx) const { - if (!measurment_cache.domain_H_field_energy_all.has_value()) + auto it = measurement_cache.domain_E_field_energy_i.find(idx); + if (it == measurement_cache.domain_E_field_energy_i.end()) { - if (A) - { - measurment_cache.domain_H_field_energy_all = dom_post_op.GetMagneticFieldEnergy(*A); - } - else if (B) - { - measurment_cache.domain_H_field_energy_all = dom_post_op.GetMagneticFieldEnergy(*B); - } - else - { - // No failure: returns zero - measurment_cache.domain_H_field_energy_all = 0.0; - } + MFEM_ABORT(fmt::format("Could not find domain index {} for E field energy!", idx)); } - return *measurment_cache.domain_H_field_energy_all; + return it->second; } -double PostOperator::GetEFieldEnergy(int idx) const +void PostOperator::MeasureEFieldEnergy() { - if (!measurment_cache.domain_E_field_energy_i.has_value()) + measurement_cache.domain_E_field_energy_i.clear(); + for (const auto &[idx, data] : dom_post_op.M_i) { - // Do all measurements - measurment_cache.domain_E_field_energy_i.emplace(); - for (const auto &[idx, data] : dom_post_op.M_i) - { - double out = 0.0; // Defaults to zero: no failure - if (V) - { - out = dom_post_op.GetDomainElectricFieldEnergy(idx, *V); - } - else if (E) - { - out = dom_post_op.GetDomainElectricFieldEnergy(idx, *E); - } - measurment_cache.domain_E_field_energy_i->emplace(idx, out); - } + measurement_cache.domain_E_field_energy_i.emplace( + idx, (!V && !E) ? 0.0 : dom_post_op.GetDomainElectricFieldEnergy(idx, V ? *V : *E)); } - auto it = measurment_cache.domain_E_field_energy_i->find(idx); - if (it == measurment_cache.domain_E_field_energy_i->end()) + + measurement_cache.domain_E_field_energy_all = + (!V && !E) ? 0.0 : dom_post_op.GetElectricFieldEnergy(V ? *V : *E); +} + +void PostOperator::MeasureHFieldEnergy() +{ + measurement_cache.domain_H_field_energy_i.clear(); + for (const auto &[idx, data] : dom_post_op.M_i) { - MFEM_ABORT(fmt::format("Could not find domain index {} for E field energy!", idx)); + measurement_cache.domain_H_field_energy_i[idx] = + (!A && !B) ? 0.0 : dom_post_op.GetDomainMagneticFieldEnergy(idx, A ? *A : *B); } - return it->second; + + measurement_cache.domain_H_field_energy_all = + (!A && !B) ? 0.0 : dom_post_op.GetMagneticFieldEnergy(A ? *A : *B); +} + +double PostOperator::GetHFieldEnergy() const +{ + return measurement_cache.domain_H_field_energy_all; } double PostOperator::GetHFieldEnergy(int idx) const { - if (!measurment_cache.domain_H_field_energy_i.has_value()) - { - // Do all measurements - measurment_cache.domain_H_field_energy_i.emplace(); - for (const auto &[idx, data] : dom_post_op.M_i) - { - double out = 0.0; // Defaults to zero: no failure - if (A) - { - out = dom_post_op.GetDomainMagneticFieldEnergy(idx, *A); - } - else if (B) - { - out = dom_post_op.GetDomainMagneticFieldEnergy(idx, *B); - } - measurment_cache.domain_H_field_energy_i->emplace(idx, out); - } - } - auto it = measurment_cache.domain_H_field_energy_i->find(idx); - if (it == measurment_cache.domain_H_field_energy_i->end()) + auto it = measurement_cache.domain_H_field_energy_i.find(idx); + if (it == measurement_cache.domain_H_field_energy_i.end()) { MFEM_ABORT(fmt::format("Could not find domain index {} for H field energy!", idx)); } return it->second; } -// Code Note: for returning the full vector we chose name GetSurfaceFluxAll() rather than -// GetSurfaceFlux(), to keep consistancy with GetEFieldEnergy(). GetEFieldEnergy() returns -// the total energy (calculated differently), not the vector of the individual -// GetHFieldEnergy(int idx). -std::vector PostOperator::GetSurfaceFluxAll() const +void PostOperator::MeasureSurfaceFlux() { // Compute the flux through a surface as Φ_j = ∫ F ⋅ n_j dS, with F = B, F = ε D, or F = // E x H. The special coefficient is used to avoid issues evaluating MFEM GridFunctions // which are discontinuous at interior boundary elements. - if (!measurment_cache.surface_flux_i.has_value()) + measurement_cache.surface_flux_i.clear(); + if (!E && !B) { - // Do all measurements - MFEM_VERIFY( - E || B, - "PostOperator needs either electric or magnetic field for flux calculation!"); - measurment_cache.surface_flux_i.emplace(); - measurment_cache.surface_flux_i->reserve(surf_post_op.flux_surfs.size()); - for (const auto &[idx, data] : surf_post_op.flux_surfs) - { - measurment_cache.surface_flux_i->emplace_back( - FluxData{idx, surf_post_op.GetSurfaceFlux(idx, E.get(), B.get()), data.type}); - } + return; + } + measurement_cache.surface_flux_i.reserve(surf_post_op.flux_surfs.size()); + for (const auto &[idx, data] : surf_post_op.flux_surfs) + { + measurement_cache.surface_flux_i.emplace_back( + FluxData{idx, surf_post_op.GetSurfaceFlux(idx, E.get(), B.get()), data.type}); } - return *measurment_cache.surface_flux_i; } PostOperator::FluxData PostOperator::GetSurfaceFlux(int idx) const { - if (!measurment_cache.surface_flux_i.has_value()) - { - GetSurfaceFluxAll(); - } - auto it = std::find_if(measurment_cache.surface_flux_i->begin(), - measurment_cache.surface_flux_i->end(), + auto it = std::find_if(measurement_cache.surface_flux_i.begin(), + measurement_cache.surface_flux_i.end(), [idx](const auto &d) { return d.idx == idx; }); - if (it == measurment_cache.surface_flux_i->end()) + if (it == measurement_cache.surface_flux_i.end()) { MFEM_ABORT(fmt::format("Could not find surface index {} for flux!", idx)); } return *it; } -std::vector PostOperator::GetInterfaceEFieldEnergyAll() const +void PostOperator::MeasureInterfaceEFieldEnergy() { // Compute the surface dielectric participation ratio and associated quality factor for // the material interface given by index idx. We have: // 1/Q_mj = p_mj tan(δ)_j // with: // p_mj = 1/2 t_j Re{∫_{Γ_j} (ε_j E_m)ᴴ E_m dS} /(E_elec + E_cap). - if (!measurment_cache.interface_eps_i.has_value()) + measurement_cache.interface_eps_i.clear(); + if (!E) { - // Do all measurements - MFEM_VERIFY(E, "Electric field solution required for E field interface energy!"); - measurment_cache.interface_eps_i.emplace(); - measurment_cache.interface_eps_i->reserve(surf_post_op.eps_surfs.size()); - for (const auto &[idx, data] : surf_post_op.eps_surfs) - { - measurment_cache.interface_eps_i->emplace_back( - InterfaceData{idx, surf_post_op.GetInterfaceElectricFieldEnergy(idx, *E), - surf_post_op.GetInterfaceLossTangent(idx)}); - } + return; + } + measurement_cache.interface_eps_i.reserve(surf_post_op.eps_surfs.size()); + for (const auto &[idx, data] : surf_post_op.eps_surfs) + { + measurement_cache.interface_eps_i.emplace_back( + InterfaceData{idx, surf_post_op.GetInterfaceElectricFieldEnergy(idx, *E), + surf_post_op.GetInterfaceLossTangent(idx)}); } - return *measurment_cache.interface_eps_i; } -PostOperator::InterfaceData PostOperator::GetInterfaceEFieldEnergy(int idx) const +const PostOperator::InterfaceData &PostOperator::GetInterfaceEFieldEnergy(int idx) const { - if (!measurment_cache.interface_eps_i.has_value()) - { - GetInterfaceEFieldEnergyAll(); - } - auto it = std::find_if(measurment_cache.interface_eps_i->begin(), - measurment_cache.interface_eps_i->end(), + auto it = std::find_if(measurement_cache.interface_eps_i.begin(), + measurement_cache.interface_eps_i.end(), [idx](const auto &d) { return d.idx == idx; }); - if (it == measurment_cache.interface_eps_i->end()) + if (it == measurement_cache.interface_eps_i.end()) { MFEM_ABORT(fmt::format("Could not find surface index {} for interface energy!", idx)); } @@ -619,21 +516,16 @@ double PostOperator::GetInterfaceParticipation(int idx, double E_m) const return data.energy / E_m; } -void PostOperator::MeasureLumpedPorts() const +void PostOperator::MeasureLumpedPorts(const LumpedPortOperator &lumped_port_op) { - MFEM_VERIFY(E && B && lumped_port_op != nullptr, - "Incorrect usage of PostOperator::MeasureLumpedPorts!"); - if (measurment_cache.lumped_port_vi.has_value()) - { - measurment_cache.lumped_port_vi->clear(); - } - else + measurement_cache.lumped_port_vi.clear(); + if (!E || !B) { - measurment_cache.lumped_port_vi.emplace(); + return; } - for (const auto &[idx, data] : *lumped_port_op) + for (const auto &[idx, data] : lumped_port_op) { - auto &vi = (*measurment_cache.lumped_port_vi)[idx]; + auto &vi = measurement_cache.lumped_port_vi[idx]; vi.P = data.GetPower(*E, *B); vi.V = data.GetVoltage(*E); if (HasImag()) @@ -666,37 +558,49 @@ void PostOperator::MeasureLumpedPorts() const vi.I[1] = vi.I[2] = vi.S = 0.0; } } -} -void PostOperator::MeasureWavePorts() const -{ - - MFEM_VERIFY(E && B && wave_port_op != nullptr, - "Incorrect usage of PostOperator::MeasureWavePorts!"); - if (measurment_cache.wave_port_vi.has_value()) + // Add contribution due to all inductive lumped boundaries in the model: + // E_ind = ∑_j 1/2 L_j I_mj². + measurement_cache.lumped_port_inductor_energy = 0.0; + for (const auto &[idx, data] : lumped_port_op) { - measurment_cache.wave_port_vi->clear(); + if (std::abs(data.L) > 0.0) + { + std::complex I_j = GetPortCurrent(idx, LumpedPortData::Branch::L); + measurement_cache.lumped_port_inductor_energy += + 0.5 * std::abs(data.L) * std::real(I_j * std::conj(I_j)); + } } - else + + // Add contribution due to all capacitive lumped boundaries in the model: + // E_cap = ∑_j 1/2 C_j V_mj². + measurement_cache.lumped_port_capacitor_energy = 0.0; + for (const auto &[idx, data] : lumped_port_op) { - measurment_cache.wave_port_vi.emplace(); + if (std::abs(data.C) > 0.0) + { + std::complex V_j = GetPortVoltage(idx); + measurement_cache.lumped_port_capacitor_energy += + 0.5 * std::abs(data.C) * std::real(V_j * std::conj(V_j)); + } } - if (!HasImag()) +} + +void PostOperator::MeasureWavePorts(const WavePortOperator &wave_port_op) +{ + measurement_cache.wave_port_vi.clear(); + // Wave ports need imaginary component. TODO: Fix this. + if (!E || !B || !HasImag()) { - return; // Wave ports need Imag; leave empty otherwise // TODO: Fix in long run + return; } - for (const auto &[idx, data] : *wave_port_op) + for (const auto &[idx, data] : wave_port_op) { - MFEM_VERIFY(measurment_cache.omega.has_value(), - "Measuring port currents with Imag fields, requires frequency to be set " - "with SetFrequency!"); - // Get value and make real: Matches current behaviour - auto omega = measurment_cache.omega->real(); - + auto omega = measurement_cache.omega.real(); MFEM_VERIFY(omega > 0.0, "Frequency domain wave port postprocessing requires nonzero frequency!"); - auto &vi = (*measurment_cache.wave_port_vi)[idx]; + auto &vi = measurement_cache.wave_port_vi[idx]; vi.P = data.GetPower(*E, *B); vi.S = data.GetSParameter(*E); vi.V = vi.I[0] = vi.I[1] = vi.I[2] = 0.0; // Not yet implemented @@ -704,144 +608,73 @@ void PostOperator::MeasureWavePorts() const } } -void PostOperator::ValidateDoPortMeasurement() const +double PostOperator::GetLumpedInductorEnergy() const { - if (!measurment_cache.lumped_port_vi.has_value()) - { - if (lumped_port_op != nullptr) - { - MeasureLumpedPorts(); - } - else - { - MFEM_ABORT("A lumped port measurement called, but the lumped port operator is not " - "defined by the solver.") - } - } - if (!measurment_cache.wave_port_vi.has_value()) - { - if (wave_port_op != nullptr) - { - MeasureWavePorts(); - } - else - { - MFEM_ABORT("A wave port measurement called, but the wave port operator is not " - "defined by the solver.") - } - } + return measurement_cache.lumped_port_inductor_energy; } -double PostOperator::GetLumpedInductorEnergy() const +double PostOperator::GetLumpedCapacitorEnergy() const { - // Add contribution due to all inductive lumped boundaries in the model: - // E_ind = ∑_j 1/2 L_j I_mj². - if (!measurment_cache.lumped_port_inductor_energy.has_value()) - { - // No failure if space has no lumped ports: Returns zero - double U = 0.0; - if (lumped_port_op != nullptr) - { - for (const auto &[idx, data] : *lumped_port_op) - { - if (std::abs(data.L) > 0.0) - { - std::complex I_j = GetPortCurrent(idx, LumpedPortData::Branch::L); - U += 0.5 * std::abs(data.L) * std::real(I_j * std::conj(I_j)); - } - } - } - measurment_cache.lumped_port_inductor_energy = U; - } - return *measurment_cache.lumped_port_inductor_energy; + return measurement_cache.lumped_port_capacitor_energy; } -double PostOperator::GetLumpedCapacitorEnergy() const +std::complex PostOperator::GetSParameter(const LumpedPortOperator &lumped_port_op, + int idx, int source_idx) const { - // Add contribution due to all capacitive lumped boundaries in the model: - // E_cap = ∑_j 1/2 C_j V_mj². - if (!measurment_cache.lumped_port_capacitor_energy.has_value()) + const LumpedPortData &data = lumped_port_op.GetPort(idx); + const LumpedPortData &src_data = lumped_port_op.GetPort(source_idx); + const auto it = measurement_cache.lumped_port_vi.find(idx); + MFEM_VERIFY(src_data.excitation, + "Lumped port index " << source_idx << " is not marked for excitation!"); + MFEM_VERIFY(it != measurement_cache.lumped_port_vi.end(), + "Could not find lumped port when calculating port S-parameters!"); + std::complex S_ij = it->second.S; + if (idx == source_idx) { - // No failure if space has no lumped ports: Returns zero - double U = 0.0; - if (lumped_port_op != nullptr) - { - for (const auto &[idx, data] : *lumped_port_op) - { - if (std::abs(data.C) > 0.0) - { - std::complex V_j = GetPortVoltage(idx); - U += 0.5 * std::abs(data.C) * std::real(V_j * std::conj(V_j)); - } - } - } - measurment_cache.lumped_port_capacitor_energy = U; + S_ij.real(S_ij.real() - 1.0); + } + // Generalized S-parameters if the ports are resistive (avoids divide-by-zero). + if (std::abs(data.R) > 0.0) + { + S_ij *= std::sqrt(src_data.R / data.R); } - return *measurment_cache.lumped_port_capacitor_energy; + return S_ij; } -std::complex PostOperator::GetSParameter(bool is_lumped_port, int idx, - int source_idx) const +std::complex PostOperator::GetSParameter(const WavePortOperator &wave_port_op, + int idx, int source_idx) const { - ValidateDoPortMeasurement(); - // TODO: In multi-excittion PR we will gurantee that lumped & wave ports have unique idx - // TODO: Merge lumped and wave port S_ij calcluations to allow both at same time. - if (is_lumped_port) + // Wave port modes are not normalized to a characteristic impedance so no generalized + // S-parameters are available. + const WavePortData &data = wave_port_op.GetPort(idx); + const WavePortData &src_data = wave_port_op.GetPort(source_idx); + const auto it = measurement_cache.wave_port_vi.find(idx); + MFEM_VERIFY(src_data.excitation, + "Wave port index " << source_idx << " is not marked for excitation!"); + MFEM_VERIFY(it != measurement_cache.wave_port_vi.end(), + "Could not find wave port when calculating port S-parameters!"); + std::complex S_ij = it->second.S; + if (idx == source_idx) { - const LumpedPortData &data = lumped_port_op->GetPort(idx); - const LumpedPortData &src_data = lumped_port_op->GetPort(source_idx); - const auto it = measurment_cache.lumped_port_vi->find(idx); - MFEM_VERIFY(src_data.excitation, - "Lumped port index " << source_idx << " is not marked for excitation!"); - MFEM_VERIFY(it != measurment_cache.lumped_port_vi->end(), - "Could not find lumped port when calculating port S-parameters!"); - std::complex S_ij = it->second.S; - if (idx == source_idx) - { - S_ij.real(S_ij.real() - 1.0); - } - // Generalized S-parameters if the ports are resistive (avoids divide-by-zero). - if (std::abs(data.R) > 0.0) - { - S_ij *= std::sqrt(src_data.R / data.R); - } - return S_ij; - } - else - { - // Wave port modes are not normalized to a characteristic impedance so no generalized - // S-parameters are available. - const WavePortData &data = wave_port_op->GetPort(idx); - const WavePortData &src_data = wave_port_op->GetPort(source_idx); - const auto it = measurment_cache.wave_port_vi->find(idx); - MFEM_VERIFY(src_data.excitation, - "Wave port index " << source_idx << " is not marked for excitation!"); - MFEM_VERIFY(it != measurment_cache.wave_port_vi->end(), - "Could not find wave port when calculating port S-parameters!"); - std::complex S_ij = it->second.S; - if (idx == source_idx) - { - S_ij.real(S_ij.real() - 1.0); - } - // Port de-embedding: S_demb = S exp(ikₙᵢ dᵢ) exp(ikₙⱼ dⱼ) (distance offset is default 0 - // unless specified). - S_ij *= std::exp(1i * src_data.kn0 * src_data.d_offset); - S_ij *= std::exp(1i * data.kn0 * data.d_offset); - return S_ij; + S_ij.real(S_ij.real() - 1.0); } + // Port de-embedding: S_demb = S exp(ikₙᵢ dᵢ) exp(ikₙⱼ dⱼ) (distance offset is default 0 + // unless specified). + S_ij *= std::exp(1i * src_data.kn0 * src_data.d_offset); + S_ij *= std::exp(1i * data.kn0 * data.d_offset); + return S_ij; } std::complex PostOperator::GetPortPower(int idx) const { - ValidateDoPortMeasurement(); - // TODO: In multi-excittion PR we will gurantee that lumped & wave ports have unique idx - auto it_lumped = measurment_cache.lumped_port_vi->find(idx); - if (it_lumped != measurment_cache.lumped_port_vi->end()) + // TODO: In multi-excitation PR we will guarantee that lumped & wave ports have unique idx + auto it_lumped = measurement_cache.lumped_port_vi.find(idx); + if (it_lumped != measurement_cache.lumped_port_vi.end()) { return it_lumped->second.P; } - auto it_wave = measurment_cache.wave_port_vi->find(idx); - if (it_wave != measurment_cache.wave_port_vi->end()) + auto it_wave = measurement_cache.wave_port_vi.find(idx); + if (it_wave != measurement_cache.wave_port_vi.end()) { return it_wave->second.P; } @@ -851,15 +684,14 @@ std::complex PostOperator::GetPortPower(int idx) const std::complex PostOperator::GetPortVoltage(int idx) const { - ValidateDoPortMeasurement(); - // TODO: In multi-excittion PR we will gurantee that lumped & wave ports have unique idx - auto it_lumped = measurment_cache.lumped_port_vi->find(idx); - if (it_lumped != measurment_cache.lumped_port_vi->end()) + // TODO: In multi-excitation PR we will guarantee that lumped & wave ports have unique idx + auto it_lumped = measurement_cache.lumped_port_vi.find(idx); + if (it_lumped != measurement_cache.lumped_port_vi.end()) { return it_lumped->second.V; } - auto it_wave = measurment_cache.wave_port_vi->find(idx); - if (it_wave != measurment_cache.wave_port_vi->end()) + auto it_wave = measurement_cache.wave_port_vi.find(idx); + if (it_wave != measurement_cache.wave_port_vi.end()) { MFEM_ABORT("GetPortVoltage is not yet implemented for wave port boundaries!"); } @@ -870,10 +702,9 @@ std::complex PostOperator::GetPortVoltage(int idx) const std::complex PostOperator::GetPortCurrent(int idx, LumpedPortData::Branch branch) const { - ValidateDoPortMeasurement(); - // TODO: In multi-excittion PR we will gurantee that lumped & wave ports have unique idx - auto it_lumped = measurment_cache.lumped_port_vi->find(idx); - if (it_lumped != measurment_cache.lumped_port_vi->end()) + // TODO: In multi-excitation PR we will guarantee that lumped & wave ports have unique idx + auto it_lumped = measurement_cache.lumped_port_vi.find(idx); + if (it_lumped != measurement_cache.lumped_port_vi.end()) { auto &I_loc = it_lumped->second.I; switch (branch) @@ -888,8 +719,8 @@ std::complex PostOperator::GetPortCurrent(int idx, return std::accumulate(I_loc.begin(), I_loc.end(), std::complex{0.0, 0.0}); } } - auto it_wave = measurment_cache.wave_port_vi->find(idx); - if (it_wave != measurment_cache.wave_port_vi->end()) + auto it_wave = measurement_cache.wave_port_vi.find(idx); + if (it_wave != measurement_cache.wave_port_vi.end()) { MFEM_ABORT("GetPortCurrent is not yet implemented for wave port boundaries!"); } @@ -897,7 +728,8 @@ std::complex PostOperator::GetPortCurrent(int idx, "Port Current: Could not find a lumped or wave port with index {}!", idx)); } -double PostOperator::GetInductorParticipation(int idx, double E_m) const +double PostOperator::GetInductorParticipation(const LumpedPortOperator &lumped_port_op, + int idx, double E_m) const { // Compute energy-participation ratio of junction given by index idx for the field mode. // We first get the port line voltage, and use lumped port circuit impedance to get peak @@ -907,17 +739,14 @@ double PostOperator::GetInductorParticipation(int idx, double E_m) const // p_mj = 1/2 L_j I_mj² / E_m. // An element with no assigned inductance will be treated as having zero admittance and // thus zero current. - if (lumped_port_op == nullptr) - { - return 0.0; - } - const LumpedPortData &data = lumped_port_op->GetPort(idx); + const LumpedPortData &data = lumped_port_op.GetPort(idx); std::complex I_mj = GetPortCurrent(idx, LumpedPortData::Branch::L); return std::copysign(0.5 * std::abs(data.L) * std::real(I_mj * std::conj(I_mj)) / E_m, I_mj.real()); // mean(I²) = (I_r² + I_i²) / 2 } -double PostOperator::GetExternalKappa(int idx, double E_m) const +double PostOperator::GetExternalKappa(const LumpedPortOperator &lumped_port_op, int idx, + double E_m) const { // Compute participation ratio of external ports (given as any port boundary with // nonzero resistance). Currently no reactance of the ports is supported. The κ of the @@ -925,11 +754,7 @@ double PostOperator::GetExternalKappa(int idx, double E_m) const // κ_mj = 1/2 R_j I_mj² / E_m // from which the mode coupling quality factor is computed as: // Q_mj = ω_m / κ_mj. - if (lumped_port_op == nullptr) - { - return 0.0; - } - const LumpedPortData &data = lumped_port_op->GetPort(idx); + const LumpedPortData &data = lumped_port_op.GetPort(idx); std::complex I_mj = GetPortCurrent(idx, LumpedPortData::Branch::R); return std::copysign(0.5 * std::abs(data.R) * std::real(I_mj * std::conj(I_mj)) / E_m, I_mj.real()); // mean(I²) = (I_r² + I_i²) / 2 @@ -1083,37 +908,25 @@ void PostOperator::WriteFieldsFinal(const ErrorIndicator *indicator) const Mpi::Barrier(GetComm()); } -std::vector> PostOperator::ProbeEField() const +void PostOperator::MeasureProbes() { - if (!measurment_cache.probe_E_field.has_value()) + if (E && interp_op.GetProbes().size() > 0) { - MFEM_VERIFY(E, "PostOperator is not configured for electric field probes!"); - if (interp_op.GetProbes().size() > 0) - { - measurment_cache.probe_E_field = interp_op.ProbeField(*E); - } - else - { - measurment_cache.probe_E_field.emplace(); - } + measurement_cache.probe_E_field = interp_op.ProbeField(*E); } - return *measurment_cache.probe_E_field; + if (B && interp_op.GetProbes().size() > 0) + { + measurement_cache.probe_B_field = interp_op.ProbeField(*B); + } +} + +std::vector> PostOperator::ProbeEField() const +{ + return measurement_cache.probe_E_field; } std::vector> PostOperator::ProbeBField() const { - if (!measurment_cache.probe_B_field.has_value()) - { - MFEM_VERIFY(B, "PostOperator is not configured for magnetic flux density probes!"); - if (interp_op.GetProbes().size() > 0) - { - measurment_cache.probe_B_field = interp_op.ProbeField(*B); - } - else - { - measurment_cache.probe_B_field.emplace(); - } - } - return *measurment_cache.probe_B_field; + return measurement_cache.probe_B_field; } } // namespace palace diff --git a/palace/models/postoperator.hpp b/palace/models/postoperator.hpp index d750b30f4..15bfeab99 100644 --- a/palace/models/postoperator.hpp +++ b/palace/models/postoperator.hpp @@ -56,10 +56,6 @@ class PostOperator SurfacePostOperator surf_post_op; // Dielectric Interface Energy and Flux mutable InterpolationOperator interp_op; // E & B fields: mutates during measure - // Port Contributions: not owned, view onto space_op only, it must not go out of scope - LumpedPortOperator *lumped_port_op = nullptr; - WavePortOperator *wave_port_op = nullptr; - // Wave port boundary mode field postprocessing. struct WavePortFieldData { @@ -93,32 +89,43 @@ class PostOperator private: struct MeasurementCache { - std::optional> omega = std::nullopt; + std::complex omega = {0.0, 0.0}; - std::optional domain_E_field_energy_all = std::nullopt; - std::optional domain_H_field_energy_all = std::nullopt; + double domain_E_field_energy_all = 0.0; + double domain_H_field_energy_all = 0.0; - std::optional> domain_E_field_energy_i = std::nullopt; - std::optional> domain_H_field_energy_i = std::nullopt; + std::map domain_E_field_energy_i; + std::map domain_H_field_energy_i; - std::optional> surface_flux_i = std::nullopt; - std::optional> interface_eps_i = std::nullopt; + std::vector surface_flux_i; + std::vector interface_eps_i; - std::optional> lumped_port_vi = std::nullopt; - std::optional> wave_port_vi = std::nullopt; + std::map lumped_port_vi; + std::map wave_port_vi; - std::optional lumped_port_inductor_energy = std::nullopt; - std::optional lumped_port_capacitor_energy = std::nullopt; + double lumped_port_inductor_energy = 0.0; + double lumped_port_capacitor_energy = 0.0; - std::optional>> probe_E_field = std::nullopt; - std::optional>> probe_B_field = std::nullopt; + std::vector> probe_E_field; + std::vector> probe_B_field; }; - mutable MeasurementCache measurment_cache = {}; + MeasurementCache measurement_cache = {}; void ValidateDoPortMeasurement() const; void InitializeDataCollection(const IoData &iodata); + // Component measurements to fill the cache. + void MeasureEFieldEnergy(); + void MeasureHFieldEnergy(); + void MeasureSurfaceFlux(); + void MeasureProbes(); + void MeasureInterfaceEFieldEnergy(); + + // Measure and cache port voltages and currents for lumped and wave port operators. + void MeasureLumpedPorts(const LumpedPortOperator &lumped_port_op); + void MeasureWavePorts(const WavePortOperator &wave_port_op); + public: PostOperator(const IoData &iodata, SpaceOperator &space_op, const std::string &name); PostOperator(const IoData &iodata, LaplaceOperator &laplace_op, const std::string &name); @@ -168,12 +175,14 @@ class PostOperator } // Function that triggers all available post-processing measurements and populate cache. + // If SpaceOperator is provided, will perform port measurements. void MeasureAll(); + void MeasureAll(const SpaceOperator &space_op); // Clear internal measurement caches void ClearAllMeasurementCache(); - // Treat the frequency, for driven and eigemode solvers, as a "measurement", that other + // Treat the frequency, for driven and eigenmode solvers, as a "measurement", that other // measurements can depend on. This has to be supplied during the solver loop separate // from the fields. void SetFrequency(double omega); @@ -194,19 +203,21 @@ class PostOperator double GetHFieldEnergy(int idx) const; // Postprocess the electric or magnetic field flux for a surface index using the computed - // electcric field and/or magnetic flux density field solutions. - std::vector GetSurfaceFluxAll() const; + // electric field and/or magnetic flux density field solutions. + std::vector GetSurfaceFluxAll() const + { + return measurement_cache.surface_flux_i; + } FluxData GetSurfaceFlux(int idx) const; - // Postprocess the partitipation ratio for interface lossy dielectric losses in the + // Postprocess the participation ratio for interface lossy dielectric losses in the // electric field mode. double GetInterfaceParticipation(int idx, double E_m) const; - std::vector GetInterfaceEFieldEnergyAll() const; - InterfaceData GetInterfaceEFieldEnergy(int idx) const; - - // Measure and cache port voltages and currents for lumped and wave port operators. - void MeasureLumpedPorts() const; - void MeasureWavePorts() const; + const std::vector &GetInterfaceEFieldEnergyAll() const + { + return measurement_cache.interface_eps_i; + } + const InterfaceData &GetInterfaceEFieldEnergy(int idx) const; // Postprocess the energy in lumped capacitor or inductor port boundaries with index in // the provided set. @@ -215,7 +226,12 @@ class PostOperator // Postprocess the S-parameter for recieving lumped or wave port index using the electric // field solution. - std::complex GetSParameter(bool is_lumped_port, int idx, int source_idx) const; + // TODO: In multi-excitation PR we will guarantee that lumped & wave ports have unique idx + // TODO: Merge lumped and wave port S_ij calculations to allow both at same time. + std::complex GetSParameter(const LumpedPortOperator &lumped_port_op, int idx, + int source_idx) const; + std::complex GetSParameter(const WavePortOperator &wave_port_op, int idx, + int source_idx) const; // Postprocess the circuit voltage and current across lumped port index using the electric // field solution. When the internal grid functions are real-valued, the returned voltage @@ -227,10 +243,12 @@ class PostOperator LumpedPortData::Branch branch = LumpedPortData::Branch::TOTAL) const; // Postprocess the EPR for the electric field solution and lumped port index. - double GetInductorParticipation(int idx, double E_m) const; + double GetInductorParticipation(const LumpedPortOperator &lumped_port_op, int idx, + double E_m) const; // Postprocess the coupling rate for radiative loss to the given I-O port index. - double GetExternalKappa(int idx, double E_m) const; + double GetExternalKappa(const LumpedPortOperator &lumped_port_op, int idx, + double E_m) const; // Write to disk the E- and B-fields extracted from the solution vectors. Note that fields // are not redimensionalized, to do so one needs to compute: B <= B * (μ₀ H₀), E <= E * From ec5342914bb40d7a5cb12419d6b8e3c4655d4062 Mon Sep 17 00:00:00 2001 From: Hugh Carson Date: Mon, 6 Jan 2025 14:24:33 -0500 Subject: [PATCH 3/6] Move simple accessors to header, gather measurements methods together in cpp --- palace/drivers/basesolver.cpp | 2 +- palace/models/postoperator.cpp | 134 ++++++++++++--------------------- palace/models/postoperator.hpp | 42 ++++++++--- 3 files changed, 80 insertions(+), 98 deletions(-) diff --git a/palace/drivers/basesolver.cpp b/palace/drivers/basesolver.cpp index db505f8f4..503fb2859 100644 --- a/palace/drivers/basesolver.cpp +++ b/palace/drivers/basesolver.cpp @@ -451,7 +451,7 @@ void BaseSolver::SurfacesPostPrinter::AddMeasurementFlux(double idx_value_dimens using fmt::format; const bool has_imaginary = post_op.HasImag(); - auto flux_data_vec = post_op.GetSurfaceFluxAll(); + auto flux_data_vec = post_op.GetSurfaceFluxes(); auto dimensionlize_flux = [&iodata](auto Phi, SurfaceFluxType flux_type) { switch (flux_type) diff --git a/palace/models/postoperator.cpp b/palace/models/postoperator.cpp index b889adf6b..0c66abd85 100644 --- a/palace/models/postoperator.cpp +++ b/palace/models/postoperator.cpp @@ -370,36 +370,6 @@ void PostOperator::MeasureAll(const SpaceOperator &space_op) MeasureWavePorts(space_op.GetWavePortOp()); } -void PostOperator::SetFrequency(double omega) -{ - measurement_cache.omega = std::complex(omega); -} - -void PostOperator::SetFrequency(std::complex omega) -{ - measurement_cache.omega = omega; -} - -std::complex PostOperator::GetFrequency() const -{ - return measurement_cache.omega; -} - -double PostOperator::GetEFieldEnergy() const -{ - return measurement_cache.domain_E_field_energy_all; -} - -double PostOperator::GetEFieldEnergy(int idx) const -{ - auto it = measurement_cache.domain_E_field_energy_i.find(idx); - if (it == measurement_cache.domain_E_field_energy_i.end()) - { - MFEM_ABORT(fmt::format("Could not find domain index {} for E field energy!", idx)); - } - return it->second; -} - void PostOperator::MeasureEFieldEnergy() { measurement_cache.domain_E_field_energy_i.clear(); @@ -426,21 +396,6 @@ void PostOperator::MeasureHFieldEnergy() (!A && !B) ? 0.0 : dom_post_op.GetMagneticFieldEnergy(A ? *A : *B); } -double PostOperator::GetHFieldEnergy() const -{ - return measurement_cache.domain_H_field_energy_all; -} - -double PostOperator::GetHFieldEnergy(int idx) const -{ - auto it = measurement_cache.domain_H_field_energy_i.find(idx); - if (it == measurement_cache.domain_H_field_energy_i.end()) - { - MFEM_ABORT(fmt::format("Could not find domain index {} for H field energy!", idx)); - } - return it->second; -} - void PostOperator::MeasureSurfaceFlux() { // Compute the flux through a surface as Φ_j = ∫ F ⋅ n_j dS, with F = B, F = ε D, or F = @@ -459,18 +414,6 @@ void PostOperator::MeasureSurfaceFlux() } } -PostOperator::FluxData PostOperator::GetSurfaceFlux(int idx) const -{ - auto it = std::find_if(measurement_cache.surface_flux_i.begin(), - measurement_cache.surface_flux_i.end(), - [idx](const auto &d) { return d.idx == idx; }); - if (it == measurement_cache.surface_flux_i.end()) - { - MFEM_ABORT(fmt::format("Could not find surface index {} for flux!", idx)); - } - return *it; -} - void PostOperator::MeasureInterfaceEFieldEnergy() { // Compute the surface dielectric participation ratio and associated quality factor for @@ -492,30 +435,6 @@ void PostOperator::MeasureInterfaceEFieldEnergy() } } -const PostOperator::InterfaceData &PostOperator::GetInterfaceEFieldEnergy(int idx) const -{ - auto it = std::find_if(measurement_cache.interface_eps_i.begin(), - measurement_cache.interface_eps_i.end(), - [idx](const auto &d) { return d.idx == idx; }); - if (it == measurement_cache.interface_eps_i.end()) - { - MFEM_ABORT(fmt::format("Could not find surface index {} for interface energy!", idx)); - } - return *it; -} - -double PostOperator::GetInterfaceParticipation(int idx, double E_m) const -{ - // Compute the surface dielectric participation ratio and associated quality factor for - // the material interface given by index idx. We have: - // 1/Q_mj = p_mj tan(δ)_j - // with: - // p_mj = 1/2 t_j Re{∫_{Γ_j} (ε_j E_m)ᴴ E_m dS} /(E_elec + E_cap). - MFEM_VERIFY(E, "Surface Q not defined, no electric field solution found!"); - auto data = GetInterfaceEFieldEnergy(idx); - return data.energy / E_m; -} - void PostOperator::MeasureLumpedPorts(const LumpedPortOperator &lumped_port_op) { measurement_cache.lumped_port_vi.clear(); @@ -607,15 +526,60 @@ void PostOperator::MeasureWavePorts(const WavePortOperator &wave_port_op) // (Z = V² / P, I = V / Z) } } +double PostOperator::GetEFieldEnergy(int idx) const +{ + auto it = measurement_cache.domain_E_field_energy_i.find(idx); + if (it == measurement_cache.domain_E_field_energy_i.end()) + { + MFEM_ABORT(fmt::format("Could not find domain index {} for E field energy!", idx)); + } + return it->second; +} + +double PostOperator::GetHFieldEnergy(int idx) const +{ + auto it = measurement_cache.domain_H_field_energy_i.find(idx); + if (it == measurement_cache.domain_H_field_energy_i.end()) + { + MFEM_ABORT(fmt::format("Could not find domain index {} for H field energy!", idx)); + } + return it->second; +} + +PostOperator::FluxData PostOperator::GetSurfaceFlux(int idx) const +{ + auto it = std::find_if(measurement_cache.surface_flux_i.begin(), + measurement_cache.surface_flux_i.end(), + [idx](const auto &d) { return d.idx == idx; }); + if (it == measurement_cache.surface_flux_i.end()) + { + MFEM_ABORT(fmt::format("Could not find surface index {} for flux!", idx)); + } + return *it; +} -double PostOperator::GetLumpedInductorEnergy() const +const PostOperator::InterfaceData &PostOperator::GetInterfaceEFieldEnergy(int idx) const { - return measurement_cache.lumped_port_inductor_energy; + auto it = std::find_if(measurement_cache.interface_eps_i.begin(), + measurement_cache.interface_eps_i.end(), + [idx](const auto &d) { return d.idx == idx; }); + if (it == measurement_cache.interface_eps_i.end()) + { + MFEM_ABORT(fmt::format("Could not find surface index {} for interface energy!", idx)); + } + return *it; } -double PostOperator::GetLumpedCapacitorEnergy() const +double PostOperator::GetInterfaceParticipation(int idx, double E_m) const { - return measurement_cache.lumped_port_capacitor_energy; + // Compute the surface dielectric participation ratio and associated quality factor for + // the material interface given by index idx. We have: + // 1/Q_mj = p_mj tan(δ)_j + // with: + // p_mj = 1/2 t_j Re{∫_{Γ_j} (ε_j E_m)ᴴ E_m dS} /(E_elec + E_cap). + MFEM_VERIFY(E, "Surface Q not defined, no electric field solution found!"); + auto data = GetInterfaceEFieldEnergy(idx); + return data.energy / E_m; } std::complex PostOperator::GetSParameter(const LumpedPortOperator &lumped_port_op, diff --git a/palace/models/postoperator.hpp b/palace/models/postoperator.hpp index 15bfeab99..dde5e9ec2 100644 --- a/palace/models/postoperator.hpp +++ b/palace/models/postoperator.hpp @@ -111,8 +111,6 @@ class PostOperator }; MeasurementCache measurement_cache = {}; - void ValidateDoPortMeasurement() const; - void InitializeDataCollection(const IoData &iodata); // Component measurements to fill the cache. @@ -185,17 +183,31 @@ class PostOperator // Treat the frequency, for driven and eigenmode solvers, as a "measurement", that other // measurements can depend on. This has to be supplied during the solver loop separate // from the fields. - void SetFrequency(double omega); - void SetFrequency(std::complex omega); + void SetFrequency(double omega) + { + measurement_cache.omega = std::complex(omega); + } + void SetFrequency(std::complex omega) + { + measurement_cache.omega = omega; + } - // Return stored frequency that was given in SetFrequency. Always promotes to complex - // frequency. - std::complex GetFrequency() const; + // Return stored frequency that was given in SetFrequency. + std::complex GetFrequency() const + { + return measurement_cache.omega; + } // Postprocess the total electric and magnetic field energies in the electric and magnetic // fields. - double GetEFieldEnergy() const; - double GetHFieldEnergy() const; + double GetEFieldEnergy() const + { + return measurement_cache.domain_E_field_energy_all; + } + double GetHFieldEnergy() const + { + return measurement_cache.domain_H_field_energy_all; + } // Postprocess the electric and magnetic field energies in the domain with the given // index. @@ -204,7 +216,7 @@ class PostOperator // Postprocess the electric or magnetic field flux for a surface index using the computed // electric field and/or magnetic flux density field solutions. - std::vector GetSurfaceFluxAll() const + std::vector GetSurfaceFluxes() const { return measurement_cache.surface_flux_i; } @@ -221,8 +233,14 @@ class PostOperator // Postprocess the energy in lumped capacitor or inductor port boundaries with index in // the provided set. - double GetLumpedInductorEnergy() const; - double GetLumpedCapacitorEnergy() const; + double GetLumpedInductorEnergy() const + { + return measurement_cache.lumped_port_inductor_energy; + } + double GetLumpedCapacitorEnergy() const + { + return measurement_cache.lumped_port_capacitor_energy; + } // Postprocess the S-parameter for recieving lumped or wave port index using the electric // field solution. From 97b09a72814df26f25a68d9d5f252b7bcd4c7dd4 Mon Sep 17 00:00:00 2001 From: Hugh Carson Date: Mon, 6 Jan 2025 14:41:58 -0500 Subject: [PATCH 4/6] Trying to fix issue with cmake cache --- cmake/ExternalMFEM.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/ExternalMFEM.cmake b/cmake/ExternalMFEM.cmake index 10a3e025a..a145eb9c0 100644 --- a/cmake/ExternalMFEM.cmake +++ b/cmake/ExternalMFEM.cmake @@ -77,7 +77,7 @@ if(CMAKE_BUILD_TYPE MATCHES "Debug|debug|DEBUG") endif() # Replace mfem abort calls with exceptions for testing, default off -set(PALACE_MFEM_USE_EXCEPTIONS CACHE NO "MFEM throw exceptsions instead of abort calls") +set(PALACE_MFEM_USE_EXCEPTIONS NO "MFEM throw exceptions instead of abort calls") set(MFEM_OPTIONS ${PALACE_SUPERBUILD_DEFAULT_ARGS}) list(APPEND MFEM_OPTIONS From 2590733482a3ef788d0e850ad5a9f77c33d48b60 Mon Sep 17 00:00:00 2001 From: Hugh Carson Date: Mon, 6 Jan 2025 16:11:37 -0500 Subject: [PATCH 5/6] Initial upgrade to remove state from printers, only driven should be complete, does not compile --- palace/drivers/basesolver.cpp | 92 +++++++++--------------------- palace/drivers/basesolver.hpp | 50 +++++------------ palace/drivers/drivensolver.cpp | 99 +++++++++++---------------------- palace/drivers/drivensolver.hpp | 19 ++----- 4 files changed, 75 insertions(+), 185 deletions(-) diff --git a/palace/drivers/basesolver.cpp b/palace/drivers/basesolver.cpp index 503fb2859..0f22caba8 100644 --- a/palace/drivers/basesolver.cpp +++ b/palace/drivers/basesolver.cpp @@ -286,14 +286,12 @@ void BaseSolver::SaveMetadata(const Timer &timer) const } } -BaseSolver::DomainsPostPrinter::DomainsPostPrinter(bool do_measurement, bool root, - const fs::path &post_dir, +BaseSolver::DomainsPostPrinter::DomainsPostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows) - : do_measurement_{do_measurement}, root_{root} { - if (!do_measurement_ || !root_) + if (!Mpi::Root(post_op.GetComm())) { return; } @@ -322,10 +320,6 @@ void BaseSolver::DomainsPostPrinter::AddMeasurement(double idx_value_dimensionfu const PostOperator &post_op, const IoData &iodata) { - if (!do_measurement_ || !root_) - { - return; - } using VT = IoData::ValueType; using fmt::format; @@ -356,26 +350,14 @@ void BaseSolver::DomainsPostPrinter::AddMeasurement(double idx_value_dimensionfu domain_E.WriteFullTableTrunc(); } -BaseSolver::SurfacesPostPrinter::SurfacesPostPrinter(bool do_measurement, bool root, - const fs::path &post_dir, +BaseSolver::SurfacesPostPrinter::SurfacesPostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows) - : root_{root}, - do_measurement_flux_(do_measurement // - && post_op.GetSurfacePostOp().flux_surfs.size() > 0 // Has flux - ), - do_measurement_eps_(do_measurement // - && post_op.GetSurfacePostOp().eps_surfs.size() > 0 // Has eps - ) { - if (!root_) - { - return; - } + if (!Mpi::Root(post_op.GetComm())) { return; } using fmt::format; - - if (do_measurement_flux_) + if (post_op.GetSurfacePostOp().flux_surfs.size() > 0) { surface_F = TableWithCSVFile(post_dir / "surface-F.csv"); surface_F.table.reserve(n_expected_rows, @@ -424,7 +406,7 @@ BaseSolver::SurfacesPostPrinter::SurfacesPostPrinter(bool do_measurement, bool r surface_F.AppendHeader(); } - if (do_measurement_eps_) + if (post_op.GetSurfacePostOp().eps_surfs.size() > 0) { surface_Q = TableWithCSVFile(post_dir / "surface-Q.csv"); surface_Q.table.reserve(n_expected_rows, @@ -443,10 +425,6 @@ void BaseSolver::SurfacesPostPrinter::AddMeasurementFlux(double idx_value_dimens const PostOperator &post_op, const IoData &iodata) { - if (!do_measurement_flux_ || !root_) - { - return; - } using VT = IoData::ValueType; using fmt::format; @@ -488,10 +466,6 @@ void BaseSolver::SurfacesPostPrinter::AddMeasurementEps(double idx_value_dimensi const PostOperator &post_op, const IoData &iodata) { - if (!do_measurement_eps_ || !root_) - { - return; - } using VT = IoData::ValueType; using fmt::format; @@ -519,32 +493,29 @@ void BaseSolver::SurfacesPostPrinter::AddMeasurement(double idx_value_dimensionf // If surfaces have been specified for postprocessing, compute the corresponding values // and write out to disk. The passed in E_elec is the sum of the E-field and lumped // capacitor energies, and E_mag is the same for the B-field and lumped inductors. - AddMeasurementFlux(idx_value_dimensionful, post_op, iodata); - AddMeasurementEps(idx_value_dimensionful, post_op, iodata); + if (post_op.GetSurfacePostOp().flux_surfs.size() > 0) + { + AddMeasurementFlux(idx_value_dimensionful, post_op, iodata); + } + if (post_op.GetSurfacePostOp().eps_surfs.size() > 0) + { + AddMeasurementEps(idx_value_dimensionful, post_op, iodata); + } } -BaseSolver::ProbePostPrinter::ProbePostPrinter(bool do_measurement, bool root, - const fs::path &post_dir, +BaseSolver::ProbePostPrinter::ProbePostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows) - : root_{root}, do_measurement_E_{do_measurement}, do_measurement_B_{do_measurement}, - has_imag{post_op.HasImag()}, v_dim{post_op.GetInterpolationOpVDim()} { #if defined(MFEM_USE_GSLIB) - do_measurement_E_ = do_measurement_E_ // - && (post_op.GetProbes().size() > 0) // Has probes defined - && post_op.HasE(); // Has E fields - - do_measurement_B_ = do_measurement_B_ // - && (post_op.GetProbes().size() > 0) // Has probes defined - && post_op.HasB(); // Has B fields - - if (!root_ || (!do_measurement_E_ && !do_measurement_B_)) + if (!Mpi::Root(post_op.GetComm()) || post_op.GetProbes().size() == 0) { return; } using fmt::format; + const int v_dim = post_op.GetInterpolationOpVDim(); + const bool has_imag = post_op.HasImag(); int scale_col = (has_imag ? 2 : 1) * v_dim; auto dim_labeler = [](int i) -> std::string { @@ -562,7 +533,7 @@ BaseSolver::ProbePostPrinter::ProbePostPrinter(bool do_measurement, bool root, } }; - if (do_measurement_E_) + if (post_op.HasE()) { probe_E = TableWithCSVFile(post_dir / "probe-E.csv"); probe_E.table.reserve(n_expected_rows, scale_col * post_op.GetProbes().size()); @@ -591,7 +562,7 @@ BaseSolver::ProbePostPrinter::ProbePostPrinter(bool do_measurement, bool root, probe_E.AppendHeader(); } - if (do_measurement_B_) + if (post_op.HasB()) { probe_B = TableWithCSVFile(post_dir / "probe-B.csv"); probe_B.table.reserve(n_expected_rows, scale_col * post_op.GetProbes().size()); @@ -626,14 +597,12 @@ void BaseSolver::ProbePostPrinter::AddMeasurementE(double idx_value_dimensionful const PostOperator &post_op, const IoData &iodata) { - if (!do_measurement_E_ || !root_) - { - return; - } using VT = IoData::ValueType; using fmt::format; auto probe_field = post_op.ProbeEField(); + const int v_dim = post_op.GetInterpolationOpVDim(); + const bool has_imag = post_op.HasImag(); MFEM_VERIFY(probe_field.size() == v_dim * post_op.GetProbes().size(), format("Size mismatch: expect vector field to ahve size {} * {} = {}; got {}", v_dim, post_op.GetProbes().size(), v_dim * post_op.GetProbes().size(), @@ -661,14 +630,12 @@ void BaseSolver::ProbePostPrinter::AddMeasurementB(double idx_value_dimensionful const PostOperator &post_op, const IoData &iodata) { - if (!do_measurement_B_ || !root_) - { - return; - } using VT = IoData::ValueType; using fmt::format; auto probe_field = post_op.ProbeBField(); + const int v_dim = post_op.GetInterpolationOpVDim(); + const bool has_imag = post_op.HasImag(); MFEM_VERIFY(probe_field.size() == v_dim * post_op.GetProbes().size(), format("Size mismatch: expect vector field to ahve size {} * {} = {}; got {}", v_dim, post_op.GetProbes().size(), v_dim * post_op.GetProbes().size(), @@ -702,15 +669,8 @@ void BaseSolver::ProbePostPrinter::AddMeasurement(double idx_value_dimensionful, #endif } -BaseSolver::ErrorIndicatorPostPrinter::ErrorIndicatorPostPrinter(bool do_measurement, - bool root, - const fs::path &post_dir) - : root_{root}, do_measurement_{do_measurement} +BaseSolver::ErrorIndicatorPostPrinter::ErrorIndicatorPostPrinter(const fs::path &post_dir) { - if (!do_measurement_ || !root_) - { - return; - } error_indicator = TableWithCSVFile(post_dir / "error-indicators.csv"); error_indicator.table.reserve(1, 4); @@ -723,7 +683,7 @@ BaseSolver::ErrorIndicatorPostPrinter::ErrorIndicatorPostPrinter(bool do_measure void BaseSolver::ErrorIndicatorPostPrinter::PrintIndicatorStatistics( const PostOperator &post_op, const ErrorIndicator::SummaryStatistics &indicator_stats) { - if (!do_measurement_ || !root_) + if (!Mpi::Root(post_op.GetComm())) { return; } diff --git a/palace/drivers/basesolver.hpp b/palace/drivers/basesolver.hpp index 370f33b02..4408bf9e6 100644 --- a/palace/drivers/basesolver.hpp +++ b/palace/drivers/basesolver.hpp @@ -33,70 +33,47 @@ class BaseSolver // Parameters for writing postprocessing outputs. fs::path post_dir; - bool root; // Common domain postprocessing for all simulation types. class DomainsPostPrinter { - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile domain_E; - public: DomainsPostPrinter() = default; - DomainsPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const PostOperator &post_op, const std::string &idx_col_name, - int n_expected_rows); - void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, - const IoData &iodata); + DomainsPostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows); + void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); }; // Common surface postprocessing for all simulation types. class SurfacesPostPrinter { - bool root_ = false; - bool do_measurement_flux_ = false; - bool do_measurement_eps_ = false; TableWithCSVFile surface_F; TableWithCSVFile surface_Q; - - public: - SurfacesPostPrinter() = default; - SurfacesPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const PostOperator &post_op, const std::string &idx_col_name, - int n_expected_rows); - void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, - const IoData &iodata); void AddMeasurementFlux(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); void AddMeasurementEps(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); + public: + SurfacesPostPrinter() = default; + SurfacesPostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows); + void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); }; // Common probe postprocessing for all simulation types. class ProbePostPrinter { - bool root_ = false; - bool do_measurement_E_ = false; - bool do_measurement_B_ = false; TableWithCSVFile probe_E; TableWithCSVFile probe_B; - int v_dim = 0; - bool has_imag = false; - - public: - ProbePostPrinter() = default; - ProbePostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const PostOperator &post_op, const std::string &idx_col_name, - int n_expected_rows); - void AddMeasurementE(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); void AddMeasurementB(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); - void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, - const IoData &iodata); + public: + ProbePostPrinter() = default; + ProbePostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows); + + void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); }; // Common error indicator postprocessing for all simulation types. // @@ -110,10 +87,9 @@ class BaseSolver public: ErrorIndicatorPostPrinter() = default; - ErrorIndicatorPostPrinter(bool do_measurement, bool root, const fs::path &post_dir); + ErrorIndicatorPostPrinter(const fs::path &post_dir); - void PrintIndicatorStatistics(const PostOperator &post_op, - const ErrorIndicator::SummaryStatistics &indicator_stats); + void PrintIndicatorStatistics(const PostOperator &post_op, const ErrorIndicator::SummaryStatistics &indicator_stats); }; // Performs a solve using the mesh sequence, then reports error indicators and the number diff --git a/palace/drivers/drivensolver.cpp b/palace/drivers/drivensolver.cpp index 3725b5c7f..89b0c012b 100644 --- a/palace/drivers/drivensolver.cpp +++ b/palace/drivers/drivensolver.cpp @@ -405,14 +405,10 @@ int DrivenSolver::GetNumSteps(double start, double end, double delta) const // Measurements / Postprocessing DrivenSolver::CurrentsPostPrinter::CurrentsPostPrinter( - bool do_measurement, bool root, const fs::path &post_dir, - const SurfaceCurrentOperator &surf_j_op, int n_expected_rows) - : root_{root}, do_measurement_{ - do_measurement // - && (surf_j_op.Size() > 0) // Needs surface currents - } + const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows) { - if (!do_measurement_ || !root_) + const auto &surf_j_op = space_op.GetSurfaceCurrentOp(); + if (!Mpi::Root(space_op.GetComm()) || surf_j_op.Size() == 0) { return; } @@ -430,10 +426,6 @@ DrivenSolver::CurrentsPostPrinter::CurrentsPostPrinter( void DrivenSolver::CurrentsPostPrinter::AddMeasurement( double freq, const SurfaceCurrentOperator &surf_j_op, const IoData &iodata) { - if (!do_measurement_ || !root_) - { - return; - } using VT = IoData::ValueType; using fmt::format; @@ -446,16 +438,12 @@ void DrivenSolver::CurrentsPostPrinter::AddMeasurement( surface_I.AppendRow(); } -DrivenSolver::PortsPostPrinter::PortsPostPrinter(bool do_measurement, bool root, - const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, +DrivenSolver::PortsPostPrinter::PortsPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, int n_expected_rows) - : root_{root}, do_measurement_{ - do_measurement // - && (lumped_port_op.Size() > 0) // Only works for lumped ports - } { - if (!do_measurement_ || !root_) + const auto &lumped_port_op = space_op.GetLumpedPortOp(); + if (!Mpi::Root(space_op.GetComm()) || lumped_port_op.Size() == 0) { return; } @@ -490,10 +478,6 @@ void DrivenSolver::PortsPostPrinter::AddMeasurement( double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata) { - if (!do_measurement_ || !root_) - { - return; - } using VT = IoData::ValueType; // Postprocess the frequency domain lumped port voltages and currents (complex magnitude @@ -528,25 +512,13 @@ void DrivenSolver::PortsPostPrinter::AddMeasurement( port_I.AppendRow(); } -DrivenSolver::SParametersPostPrinter::SParametersPostPrinter( - bool do_measurement, bool root, const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, const WavePortOperator &wave_port_op, - int n_expected_rows) - : root_{root}, - do_measurement_{ - do_measurement // - && ((lumped_port_op.Size() > 0) xor - (wave_port_op.Size() > 0)) // either lumped or wave but not both - - }, - src_lumped_port{lumped_port_op.Size() > 0} +DrivenSolver::SParametersPostPrinter::SParametersPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows) { - if (!do_measurement_ || !root_) - { - return; - } + const auto &lumped_port_op = space_op.GetLumpedPortOp(); + const auto &wave_port_op = space_op.GetWavePortOp(); + // Get excitation index as is currently done: if -1 then no excitation - // Already ensured that one of lumped or wave ports are empty + // Already ensured that one of lumped or wave ports are non-empty for (const auto &[idx, data] : lumped_port_op) { if (data.excitation) @@ -562,12 +534,12 @@ DrivenSolver::SParametersPostPrinter::SParametersPostPrinter( } } - do_measurement_ = do_measurement_ && (source_idx > 0); - - if (!do_measurement_ || !root_) + const bool do_measurement = ((lumped_port_op.Size() > 0) xor (wave_port_op.Size() > 0)) && (source_idx > 0); + if (!Mpi::Root(space_op.GetComm()) || !do_measurement) { return; } + using fmt::format; port_S = TableWithCSVFile(post_dir / "port-S.csv"); port_S.table.reserve(n_expected_rows, lumped_port_op.Size()); @@ -595,10 +567,6 @@ void DrivenSolver::SParametersPostPrinter::AddMeasurement( double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const WavePortOperator &wave_port_op, const IoData &iodata) { - if (!do_measurement_ || !root_) - { - return; - } using VT = IoData::ValueType; using fmt::format; @@ -639,18 +607,13 @@ DrivenSolver::PostprocessPrintResults::PostprocessPrintResults( bool root, const fs::path &post_dir, const PostOperator &post_op, const SpaceOperator &space_op, int n_expected_rows, int delta_post_) : delta_post{delta_post_}, write_paraview_fields{delta_post_ > 0}, - domains{true, root, post_dir, post_op, "f (GHz)", n_expected_rows}, - surfaces{true, root, post_dir, post_op, "f (GHz)", n_expected_rows}, - currents{true, root, post_dir, space_op.GetSurfaceCurrentOp(), n_expected_rows}, - probes{true, root, post_dir, post_op, "f (GHz)", n_expected_rows}, - ports{true, root, post_dir, space_op.GetLumpedPortOp(), n_expected_rows}, - s_parameters{true, - root, - post_dir, - space_op.GetLumpedPortOp(), - space_op.GetWavePortOp(), - n_expected_rows}, - error_indicator{true, root, post_dir} + domains{post_dir, post_op, "f (GHz)", n_expected_rows}, + surfaces{post_dir, post_op, "f (GHz)", n_expected_rows}, + currents{post_dir, space_op, n_expected_rows}, + probes{post_dir, post_op, "f (GHz)", n_expected_rows}, + ports{post_dir, space_op, n_expected_rows}, + s_parameters{post_dir, space_op, n_expected_rows}, + error_indicator{post_dir} { } @@ -661,14 +624,16 @@ void DrivenSolver::PostprocessPrintResults::PostprocessStep(const IoData &iodata { double omega = post_op.GetFrequency().real(); auto freq = iodata.DimensionalizeValue(IoData::ValueType::FREQUENCY, omega); - - domains.AddMeasurement(freq, post_op, iodata); - surfaces.AddMeasurement(freq, post_op, iodata); - currents.AddMeasurement(freq, space_op.GetSurfaceCurrentOp(), iodata); - probes.AddMeasurement(freq, post_op, iodata); - ports.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), iodata); - s_parameters.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), - space_op.GetWavePortOp(), iodata); + if (Mpi::Root(post_op.GetComm())) + { + domains.AddMeasurement(freq, post_op, iodata); + surfaces.AddMeasurement(freq, post_op, iodata); + currents.AddMeasurement(freq, space_op.GetSurfaceCurrentOp(), iodata); + probes.AddMeasurement(freq, post_op, iodata); + ports.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), iodata); + s_parameters.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), + space_op.GetWavePortOp(), iodata); + } // The internal GridFunctions in PostOperator have already been set: if (write_paraview_fields && (step % delta_post == 0)) { diff --git a/palace/drivers/drivensolver.hpp b/palace/drivers/drivensolver.hpp index d51bc1230..77df4f75f 100644 --- a/palace/drivers/drivensolver.hpp +++ b/palace/drivers/drivensolver.hpp @@ -32,29 +32,20 @@ class DrivenSolver : public BaseSolver class CurrentsPostPrinter { - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile surface_I; - public: CurrentsPostPrinter() = default; - CurrentsPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const SurfaceCurrentOperator &surf_j_op, int n_expected_rows); - void AddMeasurement(double freq, const SurfaceCurrentOperator &surf_j_op, - const IoData &iodata); + CurrentsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows); + void AddMeasurement(double freq, const SurfaceCurrentOperator &surf_j_op, const IoData &iodata); }; class PortsPostPrinter { - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile port_V; TableWithCSVFile port_I; - public: PortsPostPrinter() = default; - PortsPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, int n_expected_rows); + PortsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows); void AddMeasurement(double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata); }; @@ -76,9 +67,7 @@ class DrivenSolver : public BaseSolver public: SParametersPostPrinter() = default; - SParametersPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, - const WavePortOperator &wave_port_op, int n_expected_rows); + SParametersPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows); void AddMeasurement(double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const WavePortOperator &wave_port_op, const IoData &iodata); From 4630bb0619a258dfe8868879fe89099e1b054d81 Mon Sep 17 00:00:00 2001 From: Hugh Carson Date: Tue, 7 Jan 2025 10:57:11 -0500 Subject: [PATCH 6/6] Remove state from more printers. --- cmake/ExternalMFEM.cmake | 2 +- palace/drivers/basesolver.cpp | 31 +++++++++-- palace/drivers/basesolver.hpp | 31 ++++++----- palace/drivers/drivensolver.cpp | 65 +++++++++++++--------- palace/drivers/drivensolver.hpp | 19 ++++--- palace/drivers/eigensolver.cpp | 74 ++++++++++---------------- palace/drivers/eigensolver.hpp | 30 ++++------- palace/drivers/electrostaticsolver.cpp | 11 ++-- palace/drivers/electrostaticsolver.hpp | 4 +- palace/drivers/magnetostaticsolver.cpp | 11 ++-- palace/drivers/magnetostaticsolver.hpp | 4 +- palace/drivers/transientsolver.cpp | 60 +++++++++------------ palace/drivers/transientsolver.hpp | 22 +++----- palace/models/postoperator.cpp | 9 ---- palace/models/postoperator.hpp | 31 +++-------- palace/utils/tablecsv.hpp | 2 +- 16 files changed, 189 insertions(+), 217 deletions(-) diff --git a/cmake/ExternalMFEM.cmake b/cmake/ExternalMFEM.cmake index a145eb9c0..d0fe45f70 100644 --- a/cmake/ExternalMFEM.cmake +++ b/cmake/ExternalMFEM.cmake @@ -77,7 +77,7 @@ if(CMAKE_BUILD_TYPE MATCHES "Debug|debug|DEBUG") endif() # Replace mfem abort calls with exceptions for testing, default off -set(PALACE_MFEM_USE_EXCEPTIONS NO "MFEM throw exceptions instead of abort calls") +set(PALACE_MFEM_USE_EXCEPTIONS NO) set(MFEM_OPTIONS ${PALACE_SUPERBUILD_DEFAULT_ARGS}) list(APPEND MFEM_OPTIONS diff --git a/palace/drivers/basesolver.cpp b/palace/drivers/basesolver.cpp index 0f22caba8..653785628 100644 --- a/palace/drivers/basesolver.cpp +++ b/palace/drivers/basesolver.cpp @@ -320,6 +320,10 @@ void BaseSolver::DomainsPostPrinter::AddMeasurement(double idx_value_dimensionfu const PostOperator &post_op, const IoData &iodata) { + if (!Mpi::Root(post_op.GetComm())) + { + return; + } using VT = IoData::ValueType; using fmt::format; @@ -355,7 +359,10 @@ BaseSolver::SurfacesPostPrinter::SurfacesPostPrinter(const fs::path &post_dir, const std::string &idx_col_name, int n_expected_rows) { - if (!Mpi::Root(post_op.GetComm())) { return; } + if (!Mpi::Root(post_op.GetComm())) + { + return; + } using fmt::format; if (post_op.GetSurfacePostOp().flux_surfs.size() > 0) { @@ -490,6 +497,10 @@ void BaseSolver::SurfacesPostPrinter::AddMeasurement(double idx_value_dimensionf const PostOperator &post_op, const IoData &iodata) { + if (!Mpi::Root(post_op.GetComm())) + { + return; + } // If surfaces have been specified for postprocessing, compute the corresponding values // and write out to disk. The passed in E_elec is the sum of the E-field and lumped // capacitor energies, and E_mag is the same for the B-field and lumped inductors. @@ -509,7 +520,7 @@ BaseSolver::ProbePostPrinter::ProbePostPrinter(const fs::path &post_dir, int n_expected_rows) { #if defined(MFEM_USE_GSLIB) - if (!Mpi::Root(post_op.GetComm()) || post_op.GetProbes().size() == 0) + if (post_op.GetProbes().size() == 0 || !Mpi::Root(post_op.GetComm())) { return; } @@ -597,6 +608,10 @@ void BaseSolver::ProbePostPrinter::AddMeasurementE(double idx_value_dimensionful const PostOperator &post_op, const IoData &iodata) { + if (!post_op.HasE()) + { + return; + } using VT = IoData::ValueType; using fmt::format; @@ -604,7 +619,7 @@ void BaseSolver::ProbePostPrinter::AddMeasurementE(double idx_value_dimensionful const int v_dim = post_op.GetInterpolationOpVDim(); const bool has_imag = post_op.HasImag(); MFEM_VERIFY(probe_field.size() == v_dim * post_op.GetProbes().size(), - format("Size mismatch: expect vector field to ahve size {} * {} = {}; got {}", + format("Size mismatch: expect vector field to have size {} * {} = {}; got {}", v_dim, post_op.GetProbes().size(), v_dim * post_op.GetProbes().size(), probe_field.size())) @@ -630,6 +645,10 @@ void BaseSolver::ProbePostPrinter::AddMeasurementB(double idx_value_dimensionful const PostOperator &post_op, const IoData &iodata) { + if (!post_op.HasB()) + { + return; + } using VT = IoData::ValueType; using fmt::format; @@ -637,7 +656,7 @@ void BaseSolver::ProbePostPrinter::AddMeasurementB(double idx_value_dimensionful const int v_dim = post_op.GetInterpolationOpVDim(); const bool has_imag = post_op.HasImag(); MFEM_VERIFY(probe_field.size() == v_dim * post_op.GetProbes().size(), - format("Size mismatch: expect vector field to ahve size {} * {} = {}; got {}", + format("Size mismatch: expect vector field to have size {} * {} = {}; got {}", v_dim, post_op.GetProbes().size(), v_dim * post_op.GetProbes().size(), probe_field.size())) @@ -664,6 +683,10 @@ void BaseSolver::ProbePostPrinter::AddMeasurement(double idx_value_dimensionful, const IoData &iodata) { #if defined(MFEM_USE_GSLIB) + if (!Mpi::Root(post_op.GetComm()) || post_op.GetProbes().size() == 0) + { + return; + } AddMeasurementE(idx_value_dimensionful, post_op, iodata); AddMeasurementB(idx_value_dimensionful, post_op, iodata); #endif diff --git a/palace/drivers/basesolver.hpp b/palace/drivers/basesolver.hpp index 4408bf9e6..31f7bc6d1 100644 --- a/palace/drivers/basesolver.hpp +++ b/palace/drivers/basesolver.hpp @@ -33,15 +33,18 @@ class BaseSolver // Parameters for writing postprocessing outputs. fs::path post_dir; + bool root; // Common domain postprocessing for all simulation types. class DomainsPostPrinter { TableWithCSVFile domain_E; + public: - DomainsPostPrinter() = default; - DomainsPostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows); - void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); + DomainsPostPrinter(const fs::path &post_dir, const PostOperator &post_op, + const std::string &idx_col_name, int n_expected_rows); + void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, + const IoData &iodata); }; // Common surface postprocessing for all simulation types. @@ -53,10 +56,12 @@ class BaseSolver const IoData &iodata); void AddMeasurementEps(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); + public: - SurfacesPostPrinter() = default; - SurfacesPostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows); - void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); + SurfacesPostPrinter(const fs::path &post_dir, const PostOperator &post_op, + const std::string &idx_col_name, int n_expected_rows); + void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, + const IoData &iodata); }; // Common probe postprocessing for all simulation types. @@ -69,11 +74,13 @@ class BaseSolver const IoData &iodata); void AddMeasurementB(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); + public: - ProbePostPrinter() = default; - ProbePostPrinter(const fs::path &post_dir, const PostOperator &post_op, const std::string &idx_col_name, int n_expected_rows); + ProbePostPrinter(const fs::path &post_dir, const PostOperator &post_op, + const std::string &idx_col_name, int n_expected_rows); - void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, const IoData &iodata); + void AddMeasurement(double idx_value_dimensionful, const PostOperator &post_op, + const IoData &iodata); }; // Common error indicator postprocessing for all simulation types. // @@ -81,15 +88,13 @@ class BaseSolver // step (time / frequency / eigenvector). class ErrorIndicatorPostPrinter { - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile error_indicator; public: - ErrorIndicatorPostPrinter() = default; ErrorIndicatorPostPrinter(const fs::path &post_dir); - void PrintIndicatorStatistics(const PostOperator &post_op, const ErrorIndicator::SummaryStatistics &indicator_stats); + void PrintIndicatorStatistics(const PostOperator &post_op, + const ErrorIndicator::SummaryStatistics &indicator_stats); }; // Performs a solve using the mesh sequence, then reports error indicators and the number diff --git a/palace/drivers/drivensolver.cpp b/palace/drivers/drivensolver.cpp index 89b0c012b..eaf568306 100644 --- a/palace/drivers/drivensolver.cpp +++ b/palace/drivers/drivensolver.cpp @@ -401,14 +401,12 @@ int DrivenSolver::GetNumSteps(double start, double end, double delta) const (delta > 0.0 && dfinal - end < delta_eps * end)); } -// ----------------- -// Measurements / Postprocessing - -DrivenSolver::CurrentsPostPrinter::CurrentsPostPrinter( - const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows) +DrivenSolver::CurrentsPostPrinter::CurrentsPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, + int n_expected_rows) { const auto &surf_j_op = space_op.GetSurfaceCurrentOp(); - if (!Mpi::Root(space_op.GetComm()) || surf_j_op.Size() == 0) + if (surf_j_op.Size() == 0 || !Mpi::Root(space_op.GetComm())) { return; } @@ -423,9 +421,15 @@ DrivenSolver::CurrentsPostPrinter::CurrentsPostPrinter( surface_I.AppendHeader(); } -void DrivenSolver::CurrentsPostPrinter::AddMeasurement( - double freq, const SurfaceCurrentOperator &surf_j_op, const IoData &iodata) +void DrivenSolver::CurrentsPostPrinter::AddMeasurement(double freq, + const SpaceOperator &space_op, + const IoData &iodata) { + const auto &surf_j_op = space_op.GetSurfaceCurrentOp(); + if (surf_j_op.Size() == 0 || !Mpi::Root(space_op.GetComm())) + { + return; + } using VT = IoData::ValueType; using fmt::format; @@ -443,7 +447,7 @@ DrivenSolver::PortsPostPrinter::PortsPostPrinter(const fs::path &post_dir, int n_expected_rows) { const auto &lumped_port_op = space_op.GetLumpedPortOp(); - if (!Mpi::Root(space_op.GetComm()) || lumped_port_op.Size() == 0) + if (lumped_port_op.Size() == 0 || !Mpi::Root(space_op.GetComm())) { return; } @@ -478,6 +482,10 @@ void DrivenSolver::PortsPostPrinter::AddMeasurement( double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata) { + if (lumped_port_op.Size() == 0 || !Mpi::Root(post_op.GetComm())) + { + return; + } using VT = IoData::ValueType; // Postprocess the frequency domain lumped port voltages and currents (complex magnitude @@ -512,7 +520,9 @@ void DrivenSolver::PortsPostPrinter::AddMeasurement( port_I.AppendRow(); } -DrivenSolver::SParametersPostPrinter::SParametersPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows) +DrivenSolver::SParametersPostPrinter::SParametersPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, + int n_expected_rows) { const auto &lumped_port_op = space_op.GetLumpedPortOp(); const auto &wave_port_op = space_op.GetWavePortOp(); @@ -534,8 +544,9 @@ DrivenSolver::SParametersPostPrinter::SParametersPostPrinter(const fs::path &pos } } - const bool do_measurement = ((lumped_port_op.Size() > 0) xor (wave_port_op.Size() > 0)) && (source_idx > 0); - if (!Mpi::Root(space_op.GetComm()) || !do_measurement) + const bool do_measurement = + ((lumped_port_op.Size() > 0) xor (wave_port_op.Size() > 0)) && (source_idx > 0); + if (!do_measurement || !Mpi::Root(space_op.GetComm())) { return; } @@ -567,6 +578,10 @@ void DrivenSolver::SParametersPostPrinter::AddMeasurement( double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const WavePortOperator &wave_port_op, const IoData &iodata) { + if (source_idx == -1 || !Mpi::Root(post_op.GetComm())) + { + return; + } using VT = IoData::ValueType; using fmt::format; @@ -586,8 +601,9 @@ void DrivenSolver::SParametersPostPrinter::AddMeasurement( for (const auto o_idx : all_port_indices) { std::complex S_ij = - src_lumped_port ? post_op.GetSParameter(lumped_port_op, o_idx, source_idx) - : post_op.GetSParameter(wave_port_op, o_idx, source_idx); + (lumped_port_op.Size() > 0) + ? post_op.GetSParameter(lumped_port_op, o_idx, source_idx) + : post_op.GetSParameter(wave_port_op, o_idx, source_idx); auto abs_S_ij = 20.0 * std::log10(std::abs(S_ij)); auto arg_S_ij = std::arg(S_ij) * 180.0 / M_PI; @@ -612,8 +628,7 @@ DrivenSolver::PostprocessPrintResults::PostprocessPrintResults( currents{post_dir, space_op, n_expected_rows}, probes{post_dir, post_op, "f (GHz)", n_expected_rows}, ports{post_dir, space_op, n_expected_rows}, - s_parameters{post_dir, space_op, n_expected_rows}, - error_indicator{post_dir} + s_parameters{post_dir, space_op, n_expected_rows}, error_indicator{post_dir} { } @@ -624,16 +639,14 @@ void DrivenSolver::PostprocessPrintResults::PostprocessStep(const IoData &iodata { double omega = post_op.GetFrequency().real(); auto freq = iodata.DimensionalizeValue(IoData::ValueType::FREQUENCY, omega); - if (Mpi::Root(post_op.GetComm())) - { - domains.AddMeasurement(freq, post_op, iodata); - surfaces.AddMeasurement(freq, post_op, iodata); - currents.AddMeasurement(freq, space_op.GetSurfaceCurrentOp(), iodata); - probes.AddMeasurement(freq, post_op, iodata); - ports.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), iodata); - s_parameters.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), - space_op.GetWavePortOp(), iodata); - } + domains.AddMeasurement(freq, post_op, iodata); + surfaces.AddMeasurement(freq, post_op, iodata); + currents.AddMeasurement(freq, space_op, iodata); + probes.AddMeasurement(freq, post_op, iodata); + ports.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), iodata); + s_parameters.AddMeasurement(freq, post_op, space_op.GetLumpedPortOp(), + space_op.GetWavePortOp(), iodata); + // The internal GridFunctions in PostOperator have already been set: if (write_paraview_fields && (step % delta_post == 0)) { diff --git a/palace/drivers/drivensolver.hpp b/palace/drivers/drivensolver.hpp index 77df4f75f..f11e10823 100644 --- a/palace/drivers/drivensolver.hpp +++ b/palace/drivers/drivensolver.hpp @@ -33,19 +33,21 @@ class DrivenSolver : public BaseSolver class CurrentsPostPrinter { TableWithCSVFile surface_I; + public: - CurrentsPostPrinter() = default; - CurrentsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows); - void AddMeasurement(double freq, const SurfaceCurrentOperator &surf_j_op, const IoData &iodata); + CurrentsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, + int n_expected_rows); + void AddMeasurement(double freq, const SpaceOperator &space_op, const IoData &iodata); }; class PortsPostPrinter { TableWithCSVFile port_V; TableWithCSVFile port_I; + public: - PortsPostPrinter() = default; - PortsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows); + PortsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, + int n_expected_rows); void AddMeasurement(double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata); }; @@ -56,9 +58,6 @@ class DrivenSolver : public BaseSolver // excited port index specified in the configuration file, storing |S_ij| and arg // (S_ij) in dB and degrees, respectively. S-parameter output is only available for a // single lumped or wave port excitation. - - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile port_S; // Currently can't mix lumped and surface ports for s-matrix @@ -66,8 +65,8 @@ class DrivenSolver : public BaseSolver int source_idx = -1; public: - SParametersPostPrinter() = default; - SParametersPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_expected_rows); + SParametersPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, + int n_expected_rows); void AddMeasurement(double freq, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const WavePortOperator &wave_port_op, const IoData &iodata); diff --git a/palace/drivers/eigensolver.cpp b/palace/drivers/eigensolver.cpp index 80f3761dc..9f4423b24 100644 --- a/palace/drivers/eigensolver.cpp +++ b/palace/drivers/eigensolver.cpp @@ -41,7 +41,7 @@ EigenSolver::Solve(const std::vector> &mesh) const // Configure objects for postprocessing. PostOperator post_op(iodata, space_op, "eigenmode"); - PostprocessPrintResults post_results(root, post_dir, post_op, space_op, + PostprocessPrintResults post_results(post_dir, post_op, space_op, iodata.solver.eigenmode.n_post); ComplexVector E(Curl.Width()), B(Curl.Height()); E.UseDevice(true); @@ -351,7 +351,6 @@ void EigenSolver::EigenPostPrinter::PrintStdoutHeader() eig.table.col_options.min_left_padding = 6; // Separate printing due to printing lead as integer not float - fmt::memory_buffer buf; auto to = [&buf](auto f, auto &&...a) { fmt::format_to(std::back_inserter(buf), f, std::forward(a)...); }; @@ -367,7 +366,7 @@ void EigenSolver::EigenPostPrinter::PrintStdoutHeader() } to("{:s}", eig.table.print_row_separator); - Mpi::Print("{}{}", std::string{buf.data(), buf.size()}, + Mpi::Print("{}{}\n", std::string{buf.data(), buf.size()}, std::string(stdout_int_print_width + 4 * eig.table[1].col_width(), '=')); eig.table.col_options = save_defaults; } @@ -387,7 +386,7 @@ void EigenSolver::EigenPostPrinter::PrintStdoutRow(size_t j) auto to = [&buf](auto f, auto &&...a) { fmt::format_to(std::back_inserter(buf), f, std::forward(a)...); }; - to("{:{}d}", int(eig.table[0].data[j]), stdout_int_print_width); + to("{:{}d}", int(eig.table[0].data.at(j)), stdout_int_print_width); for (int i = 1; i < eig.table.n_cols(); i++) { if (i > 0) @@ -397,18 +396,18 @@ void EigenSolver::EigenPostPrinter::PrintStdoutRow(size_t j) to("{:s}", eig.table[i].format_row(j)); } to("{:s}", eig.table.print_row_separator); - Mpi::Print("{}", buf); + Mpi::Print("{}", fmt::to_string(buf)); eig.table.col_options = save_defaults; } -EigenSolver::EigenPostPrinter::EigenPostPrinter(bool do_measurement, bool root, - const fs::path &post_dir, int n_post) - : root_{root}, do_measurement_(do_measurement), +EigenSolver::EigenPostPrinter::EigenPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, int n_post) + : root_(Mpi::Root(space_op.GetComm())), stdout_int_print_width(1 + static_cast(std::log10(n_post))) { // Note: we switch to n_eig rather than n_conv for padding since we don't know n_conv // until solve - if (!do_measurement_ || !root_) + if (!root_) { return; } @@ -428,7 +427,7 @@ void EigenSolver::EigenPostPrinter::AddMeasurement(int eigen_print_idx, double error_bkwd, double error_abs, const IoData &iodata) { - if (!do_measurement_ || !root_) + if (!root_) { return; } @@ -450,16 +449,12 @@ void EigenSolver::EigenPostPrinter::AddMeasurement(int eigen_print_idx, PrintStdoutRow(eig.table.n_rows() - 1); } -EigenSolver::PortsPostPrinter::PortsPostPrinter(bool do_measurement, bool root, - const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, +EigenSolver::PortsPostPrinter::PortsPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, int n_expected_rows) - : root_{root}, do_measurement_{ - do_measurement // - && (lumped_port_op.Size() > 0) // - } { - if (!do_measurement_ || !root_) + const auto &lumped_port_op = space_op.GetLumpedPortOp(); + if (lumped_port_op.Size() == 0 || !Mpi::Root(space_op.GetComm())) { return; } @@ -489,7 +484,7 @@ void EigenSolver::PortsPostPrinter::AddMeasurement(int eigen_print_idx, const LumpedPortOperator &lumped_port_op, const IoData &iodata) { - if (!do_measurement_ || !root_) + if (lumped_port_op.Size() == 0 || !Mpi::Root(post_op.GetComm())) { return; } @@ -518,38 +513,31 @@ void EigenSolver::PortsPostPrinter::AddMeasurement(int eigen_print_idx, port_I.AppendRow(); } -EigenSolver::EPRPostPrinter::EPRPostPrinter(bool do_measurement, bool root, - const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, +EigenSolver::EPRPostPrinter::EPRPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, int n_expected_rows) - : root_{root}, do_measurement_EPR_(do_measurement // - && lumped_port_op.Size() > 0), - do_measurement_Q_(do_measurement_EPR_) { + const auto &lumped_port_op = space_op.GetLumpedPortOp(); // Mode EPR for lumped inductor elements: - for (const auto &[idx, data] : lumped_port_op) { - if (std::abs(data.L) > 0.) + if (std::abs(data.L) > 0.0) { ports_with_L.push_back(idx); } - if (std::abs(data.R) > 0.) + if (std::abs(data.R) > 0.0) { ports_with_R.push_back(idx); } } - do_measurement_EPR_ = do_measurement_EPR_ && !ports_with_L.empty(); - do_measurement_Q_ = do_measurement_Q_ && !ports_with_R.empty(); - - if (!root_ || (!do_measurement_EPR_ && !do_measurement_Q_)) + if ((ports_with_L.empty() && ports_with_R.empty()) || !Mpi::Root(space_op.GetComm())) { return; } using fmt::format; - if (do_measurement_EPR_) + if (!ports_with_L.empty()) { port_EPR = TableWithCSVFile(post_dir / "port-EPR.csv"); port_EPR.table.reserve(n_expected_rows, 1 + ports_with_L.size()); @@ -560,7 +548,7 @@ EigenSolver::EPRPostPrinter::EPRPostPrinter(bool do_measurement, bool root, } port_EPR.AppendHeader(); } - if (do_measurement_Q_) + if (!ports_with_R.empty()) { port_Q = TableWithCSVFile(post_dir / "port-Q.csv"); port_Q.table.reserve(n_expected_rows, 1 + ports_with_R.size()); @@ -578,7 +566,7 @@ void EigenSolver::EPRPostPrinter::AddMeasurementEPR( double eigen_print_idx, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata) { - if (!do_measurement_EPR_ || !root_) + if (ports_with_L.empty() || !Mpi::Root(post_op.GetComm())) { return; } @@ -602,7 +590,7 @@ void EigenSolver::EPRPostPrinter::AddMeasurementQ(double eigen_print_idx, const LumpedPortOperator &lumped_port_op, const IoData &iodata) { - if (!do_measurement_Q_ || !root_) + if (ports_with_R.empty() || !Mpi::Root(post_op.GetComm())) { return; } @@ -635,17 +623,14 @@ void EigenSolver::EPRPostPrinter::AddMeasurement(double eigen_print_idx, AddMeasurementQ(eigen_print_idx, post_op, lumped_port_op, iodata); } -EigenSolver::PostprocessPrintResults::PostprocessPrintResults(bool root, - const fs::path &post_dir, +EigenSolver::PostprocessPrintResults::PostprocessPrintResults(const fs::path &post_dir, const PostOperator &post_op, const SpaceOperator &space_op, int n_post_) : n_post(n_post_), write_paraview_fields(n_post_ > 0), - domains{true, root, post_dir, post_op, "m", n_post}, - surfaces{true, root, post_dir, post_op, "m", n_post}, - probes{true, root, post_dir, post_op, "m", n_post}, eigen{true, root, post_dir, n_post}, - epr{true, root, post_dir, space_op.GetLumpedPortOp(), n_post}, - error_indicator{true, root, post_dir} + domains{post_dir, post_op, "m", n_post}, surfaces{post_dir, post_op, "m", n_post}, + probes{post_dir, post_op, "m", n_post}, eigen{post_dir, space_op, n_post}, + epr{post_dir, space_op, n_post}, error_indicator{post_dir} { } @@ -656,16 +641,15 @@ void EigenSolver::PostprocessPrintResults::PostprocessStep(const IoData &iodata, double error_bkward) { int eigen_print_idx = step + 1; - domains.AddMeasurement(eigen_print_idx, post_op, iodata); surfaces.AddMeasurement(eigen_print_idx, post_op, iodata); probes.AddMeasurement(eigen_print_idx, post_op, iodata); eigen.AddMeasurement(eigen_print_idx, post_op, error_bkward, error_abs, iodata); epr.AddMeasurement(eigen_print_idx, post_op, space_op.GetLumpedPortOp(), iodata); + // The internal GridFunctions in PostOperator have already been set: if (write_paraview_fields && step < n_post) { - Mpi::Print("\n"); post_op.WriteFields(step, eigen_print_idx); Mpi::Print(" Wrote mode {:d} to disk\n", eigen_print_idx); } diff --git a/palace/drivers/eigensolver.hpp b/palace/drivers/eigensolver.hpp index 81fec562c..c42f301a3 100644 --- a/palace/drivers/eigensolver.hpp +++ b/palace/drivers/eigensolver.hpp @@ -27,7 +27,6 @@ class EigenSolver : public BaseSolver struct EigenPostPrinter { bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile eig; // Print data to stdout with custom table formatting @@ -37,49 +36,39 @@ class EigenSolver : public BaseSolver public: int stdout_int_print_width = 0; - EigenPostPrinter() = default; - EigenPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, int n_post); + EigenPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, int n_post); void AddMeasurement(int eigen_print_idx, const PostOperator &post_op, double error_bkwd, double error_abs, const IoData &iodata); }; class PortsPostPrinter { - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile port_V; TableWithCSVFile port_I; public: - PortsPostPrinter() = default; - PortsPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, int n_expected_rows); + PortsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, + int n_expected_rows); void AddMeasurement(int eigen_print_idx, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata); }; - // Common domain postprocessing for all simulation types. class EPRPostPrinter { - bool root_ = false; - bool do_measurement_EPR_ = false; - bool do_measurement_Q_ = false; TableWithCSVFile port_EPR; TableWithCSVFile port_Q; std::vector ports_with_L; std::vector ports_with_R; - - public: - EPRPostPrinter() = default; - EPRPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, int n_expected_rows); - void AddMeasurementEPR(double eigen_print_idx, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata); void AddMeasurementQ(double eigen_print_idx, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata); + public: + EPRPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, + int n_expected_rows); + void AddMeasurement(double eigen_print_idx, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata); }; @@ -97,9 +86,8 @@ class EigenSolver : public BaseSolver ErrorIndicatorPostPrinter error_indicator; - PostprocessPrintResults(bool is_mpi_root, const fs::path &post_dir, - const PostOperator &post_op, const SpaceOperator &space_op, - int n_post_); + PostprocessPrintResults(const fs::path &post_dir, const PostOperator &post_op, + const SpaceOperator &space_op, int n_post_); void PostprocessStep(const IoData &iodata, const PostOperator &post_op, const SpaceOperator &space_op, int step, double error_abs, double error_bkward); diff --git a/palace/drivers/electrostaticsolver.cpp b/palace/drivers/electrostaticsolver.cpp index 5efa5af9a..40e984443 100644 --- a/palace/drivers/electrostaticsolver.cpp +++ b/palace/drivers/electrostaticsolver.cpp @@ -40,7 +40,7 @@ ElectrostaticSolver::Solve(const std::vector> &mesh) const PostOperator post_op(iodata, laplace_op, "electrostatic"); int n_step = static_cast(laplace_op.GetSources().size()); MFEM_VERIFY(n_step > 0, "No terminal boundaries specified for electrostatic simulation!"); - PostprocessPrintResults post_results(root, post_dir, post_op, + PostprocessPrintResults post_results(post_dir, post_op, iodata.solver.electrostatic.n_post); // Right-hand side term and solution vector storage. @@ -202,12 +202,10 @@ void ElectrostaticSolver::PostprocessTerminals( } ElectrostaticSolver::PostprocessPrintResults::PostprocessPrintResults( - bool root, const fs::path &post_dir, const PostOperator &post_op, int n_post_) + const fs::path &post_dir, const PostOperator &post_op, int n_post_) : n_post(n_post_), write_paraview_fields(n_post_ > 0), - domains{true, root, post_dir, post_op, "i", n_post}, - surfaces{true, root, post_dir, post_op, "i", n_post}, - probes{true, root, post_dir, post_op, "i", n_post}, - error_indicator{true, root, post_dir} + domains{post_dir, post_op, "i", n_post}, surfaces{post_dir, post_op, "i", n_post}, + probes{post_dir, post_op, "i", n_post}, error_indicator{post_dir} { } @@ -217,6 +215,7 @@ void ElectrostaticSolver::PostprocessPrintResults::PostprocessStep( domains.AddMeasurement(idx, post_op, iodata); surfaces.AddMeasurement(idx, post_op, iodata); probes.AddMeasurement(idx, post_op, iodata); + // The internal GridFunctions in PostOperator have already been set from V: if (write_paraview_fields && step < n_post) { diff --git a/palace/drivers/electrostaticsolver.hpp b/palace/drivers/electrostaticsolver.hpp index 283d6c540..21f2be2c6 100644 --- a/palace/drivers/electrostaticsolver.hpp +++ b/palace/drivers/electrostaticsolver.hpp @@ -42,8 +42,8 @@ class ElectrostaticSolver : public BaseSolver ErrorIndicatorPostPrinter error_indicator; - PostprocessPrintResults(bool is_mpi_root, const fs::path &post_dir, - const PostOperator &post_op, int n_post_); + PostprocessPrintResults(const fs::path &post_dir, const PostOperator &post_op, + int n_post_); void PostprocessStep(const IoData &iodata, const PostOperator &post_op, int step, int idx); void PostprocessFinal(const PostOperator &post_op, const ErrorIndicator &indicator); diff --git a/palace/drivers/magnetostaticsolver.cpp b/palace/drivers/magnetostaticsolver.cpp index f4321daf2..221596cae 100644 --- a/palace/drivers/magnetostaticsolver.cpp +++ b/palace/drivers/magnetostaticsolver.cpp @@ -40,7 +40,7 @@ MagnetostaticSolver::Solve(const std::vector> &mesh) const int n_step = static_cast(curlcurl_op.GetSurfaceCurrentOp().Size()); MFEM_VERIFY(n_step > 0, "No surface current boundaries specified for magnetostatic simulation!"); - PostprocessPrintResults post_results(root, post_dir, post_op, + PostprocessPrintResults post_results(post_dir, post_op, iodata.solver.magnetostatic.n_post); // Source term and solution vector storage. @@ -207,12 +207,10 @@ void MagnetostaticSolver::PostprocessTerminals(PostOperator &post_op, } MagnetostaticSolver::PostprocessPrintResults::PostprocessPrintResults( - bool root, const fs::path &post_dir, const PostOperator &post_op, int n_post_) + const fs::path &post_dir, const PostOperator &post_op, int n_post_) : n_post(n_post_), write_paraview_fields(n_post_ > 0), - domains{true, root, post_dir, post_op, "i", n_post}, - surfaces{true, root, post_dir, post_op, "i", n_post}, - probes{true, root, post_dir, post_op, "i", n_post}, - error_indicator{true, root, post_dir} + domains{post_dir, post_op, "i", n_post}, surfaces{post_dir, post_op, "i", n_post}, + probes{post_dir, post_op, "i", n_post}, error_indicator{post_dir} { } @@ -222,6 +220,7 @@ void MagnetostaticSolver::PostprocessPrintResults::PostprocessStep( domains.AddMeasurement(idx, post_op, iodata); surfaces.AddMeasurement(idx, post_op, iodata); probes.AddMeasurement(idx, post_op, iodata); + // The internal GridFunctions in PostOperator have already been set from A: if (write_paraview_fields && step < n_post) { diff --git a/palace/drivers/magnetostaticsolver.hpp b/palace/drivers/magnetostaticsolver.hpp index 608526c24..d8e660a72 100644 --- a/palace/drivers/magnetostaticsolver.hpp +++ b/palace/drivers/magnetostaticsolver.hpp @@ -34,8 +34,8 @@ class MagnetostaticSolver : public BaseSolver ErrorIndicatorPostPrinter error_indicator; - PostprocessPrintResults(bool is_mpi_root, const fs::path &post_dir, - const PostOperator &post_op, int n_post_); + PostprocessPrintResults(const fs::path &post_dir, const PostOperator &post_op, + int n_post_); void PostprocessStep(const IoData &iodata, const PostOperator &post_op, int step, int idx); void PostprocessFinal(const PostOperator &post_op, const ErrorIndicator &indicator); diff --git a/palace/drivers/transientsolver.cpp b/palace/drivers/transientsolver.cpp index b1f15d2de..ac3746f00 100644 --- a/palace/drivers/transientsolver.cpp +++ b/palace/drivers/transientsolver.cpp @@ -38,7 +38,7 @@ TransientSolver::Solve(const std::vector> &mesh) const // Time stepping is uniform in the time domain. Index sets are for computing things like // port voltages and currents in postprocessing. PostOperator post_op(iodata, space_op, "transient"); - PostprocessPrintResults post_results(root, post_dir, post_op, space_op, n_step, + PostprocessPrintResults post_results(post_dir, post_op, space_op, n_step, iodata.solver.transient.delta_post); { @@ -244,18 +244,12 @@ int TransientSolver::GetNumSteps(double start, double end, double delta) const (delta > 0.0 && dfinal - end < delta_eps * end)); } -// ----------------- -// Measurements / Postprocessing - -TransientSolver::CurrentsPostPrinter::CurrentsPostPrinter( - bool do_measurement, bool root, const fs::path &post_dir, - const SurfaceCurrentOperator &surf_j_op, int n_expected_rows) - : root_{root}, // - do_measurement_(do_measurement // - && (surf_j_op.Size() > 0) // Needs surface currents - ) +TransientSolver::CurrentsPostPrinter::CurrentsPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, + int n_expected_rows) { - if (!do_measurement_ || !root_) + const auto &surf_j_op = space_op.GetSurfaceCurrentOp(); + if (surf_j_op.Size() == 0 || !Mpi::Root(space_op.GetComm())) { return; } @@ -271,10 +265,12 @@ TransientSolver::CurrentsPostPrinter::CurrentsPostPrinter( surface_I.AppendHeader(); } -void TransientSolver::CurrentsPostPrinter::AddMeasurement( - double t, double J_coef, const SurfaceCurrentOperator &surf_j_op, const IoData &iodata) +void TransientSolver::CurrentsPostPrinter::AddMeasurement(double t, double J_coef, + const SpaceOperator &space_op, + const IoData &iodata) { - if (!do_measurement_ || !root_) + const auto &surf_j_op = space_op.GetSurfaceCurrentOp(); + if (surf_j_op.Size() == 0 || !Mpi::Root(space_op.GetComm())) { return; } @@ -290,15 +286,12 @@ void TransientSolver::CurrentsPostPrinter::AddMeasurement( surface_I.AppendRow(); } -TransientSolver::PortsPostPrinter::PortsPostPrinter( - bool do_measurement, bool root, const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, int n_expected_rows) - : root_{root}, do_measurement_{ - do_measurement // - && (lumped_port_op.Size() > 0) // Only works for lumped ports - } +TransientSolver::PortsPostPrinter::PortsPostPrinter(const fs::path &post_dir, + const SpaceOperator &space_op, + int n_expected_rows) { - if (!do_measurement_ || !root_) + const auto &lumped_port_op = space_op.GetLumpedPortOp(); + if (lumped_port_op.Size() == 0 || !Mpi::Root(space_op.GetComm())) { return; } @@ -329,7 +322,7 @@ void TransientSolver::PortsPostPrinter::AddMeasurement( double t, double J_coef, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata) { - if (!do_measurement_ || !root_) + if (lumped_port_op.Size() == 0 || !Mpi::Root(post_op.GetComm())) { return; } @@ -369,15 +362,14 @@ void TransientSolver::PortsPostPrinter::AddMeasurement( } TransientSolver::PostprocessPrintResults::PostprocessPrintResults( - bool root, const fs::path &post_dir, const PostOperator &post_op, - const SpaceOperator &space_op, int n_expected_rows, int delta_post_) + const fs::path &post_dir, const PostOperator &post_op, const SpaceOperator &space_op, + int n_expected_rows, int delta_post_) : delta_post{delta_post_}, write_paraview_fields(delta_post_ > 0), - domains{true, root, post_dir, post_op, "t (ns)", n_expected_rows}, - surfaces{true, root, post_dir, post_op, "t (ns)", n_expected_rows}, - currents{true, root, post_dir, space_op.GetSurfaceCurrentOp(), n_expected_rows}, - probes{true, root, post_dir, post_op, "t (ns)", n_expected_rows}, - ports{true, root, post_dir, space_op.GetLumpedPortOp(), n_expected_rows}, - error_indicator{true, root, post_dir} + domains{post_dir, post_op, "t (ns)", n_expected_rows}, + surfaces{post_dir, post_op, "t (ns)", n_expected_rows}, + currents{post_dir, space_op, n_expected_rows}, + probes{post_dir, post_op, "t (ns)", n_expected_rows}, + ports{post_dir, space_op, n_expected_rows}, error_indicator{post_dir} { } @@ -386,12 +378,12 @@ void TransientSolver::PostprocessPrintResults::PostprocessStep( int step, double t, double J_coef) { auto time = iodata.DimensionalizeValue(IoData::ValueType::TIME, t); - domains.AddMeasurement(time, post_op, iodata); surfaces.AddMeasurement(time, post_op, iodata); - currents.AddMeasurement(t, J_coef, space_op.GetSurfaceCurrentOp(), iodata); + currents.AddMeasurement(t, J_coef, space_op, iodata); probes.AddMeasurement(time, post_op, iodata); ports.AddMeasurement(t, J_coef, post_op, space_op.GetLumpedPortOp(), iodata); + // The internal GridFunctions in PostOperator have already been set: if (write_paraview_fields && (step % delta_post == 0)) { diff --git a/palace/drivers/transientsolver.hpp b/palace/drivers/transientsolver.hpp index ee28e0c38..d03cdf2b4 100644 --- a/palace/drivers/transientsolver.hpp +++ b/palace/drivers/transientsolver.hpp @@ -31,29 +31,23 @@ class TransientSolver : public BaseSolver class CurrentsPostPrinter { - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile surface_I; public: - CurrentsPostPrinter() = default; - CurrentsPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const SurfaceCurrentOperator &surf_j_op, int n_expected_rows); - void AddMeasurement(double t, double J_coef, const SurfaceCurrentOperator &surf_j_op, + CurrentsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, + int n_expected_rows); + void AddMeasurement(double t, double J_coef, const SpaceOperator &space_op, const IoData &iodata); }; class PortsPostPrinter { - bool root_ = false; - bool do_measurement_ = false; TableWithCSVFile port_V; TableWithCSVFile port_I; public: - PortsPostPrinter() = default; - PortsPostPrinter(bool do_measurement, bool root, const fs::path &post_dir, - const LumpedPortOperator &lumped_port_op, int n_expected_rows); + PortsPostPrinter(const fs::path &post_dir, const SpaceOperator &space_op, + int n_expected_rows); void AddMeasurement(double t, double J_coef, const PostOperator &post_op, const LumpedPortOperator &lumped_port_op, const IoData &iodata); }; @@ -71,9 +65,9 @@ class TransientSolver : public BaseSolver ErrorIndicatorPostPrinter error_indicator; - PostprocessPrintResults(bool is_mpi_root, const fs::path &post_dir, - const PostOperator &post_op, const SpaceOperator &space_op, - int n_expected_rows, int delta_post); + PostprocessPrintResults(const fs::path &post_dir, const PostOperator &post_op, + const SpaceOperator &space_op, int n_expected_rows, + int delta_post); void PostprocessStep(const IoData &iodata, const PostOperator &post_op, const SpaceOperator &space_op, int step, double t, double J_coef); void PostprocessFinal(const PostOperator &post_op, const ErrorIndicator &indicator); diff --git a/palace/models/postoperator.cpp b/palace/models/postoperator.cpp index 0c66abd85..2e1384c71 100644 --- a/palace/models/postoperator.cpp +++ b/palace/models/postoperator.cpp @@ -572,11 +572,6 @@ const PostOperator::InterfaceData &PostOperator::GetInterfaceEFieldEnergy(int id double PostOperator::GetInterfaceParticipation(int idx, double E_m) const { - // Compute the surface dielectric participation ratio and associated quality factor for - // the material interface given by index idx. We have: - // 1/Q_mj = p_mj tan(δ)_j - // with: - // p_mj = 1/2 t_j Re{∫_{Γ_j} (ε_j E_m)ᴴ E_m dS} /(E_elec + E_cap). MFEM_VERIFY(E, "Surface Q not defined, no electric field solution found!"); auto data = GetInterfaceEFieldEnergy(idx); return data.energy / E_m; @@ -789,8 +784,6 @@ void PostOperator::WriteFields(int step, double time) const paraview_bdr.Save(); mesh::NondimensionalizeMesh(mesh, mesh_Lc0); ScaleGridFunctions(1.0 / mesh_Lc0, mesh.Dimension(), HasImag(), E, B, V, A); - - Mpi::Barrier(GetComm()); } void PostOperator::WriteFieldsFinal(const ErrorIndicator *indicator) const @@ -868,8 +861,6 @@ void PostOperator::WriteFieldsFinal(const ErrorIndicator *indicator) const paraview.RegisterVCoeffField(name, gf); } mesh::NondimensionalizeMesh(mesh, mesh_Lc0); - - Mpi::Barrier(GetComm()); } void PostOperator::MeasureProbes() diff --git a/palace/models/postoperator.hpp b/palace/models/postoperator.hpp index dde5e9ec2..ed6ff645d 100644 --- a/palace/models/postoperator.hpp +++ b/palace/models/postoperator.hpp @@ -173,7 +173,7 @@ class PostOperator } // Function that triggers all available post-processing measurements and populate cache. - // If SpaceOperator is provided, will perform port measurements. + // If SpaceOperator is provided, will perform any port measurements. void MeasureAll(); void MeasureAll(const SpaceOperator &space_op); @@ -183,31 +183,16 @@ class PostOperator // Treat the frequency, for driven and eigenmode solvers, as a "measurement", that other // measurements can depend on. This has to be supplied during the solver loop separate // from the fields. - void SetFrequency(double omega) - { - measurement_cache.omega = std::complex(omega); - } - void SetFrequency(std::complex omega) - { - measurement_cache.omega = omega; - } + void SetFrequency(double omega) { measurement_cache.omega = std::complex(omega); } + void SetFrequency(std::complex omega) { measurement_cache.omega = omega; } // Return stored frequency that was given in SetFrequency. - std::complex GetFrequency() const - { - return measurement_cache.omega; - } + std::complex GetFrequency() const { return measurement_cache.omega; } // Postprocess the total electric and magnetic field energies in the electric and magnetic // fields. - double GetEFieldEnergy() const - { - return measurement_cache.domain_E_field_energy_all; - } - double GetHFieldEnergy() const - { - return measurement_cache.domain_H_field_energy_all; - } + double GetEFieldEnergy() const { return measurement_cache.domain_E_field_energy_all; } + double GetHFieldEnergy() const { return measurement_cache.domain_H_field_energy_all; } // Postprocess the electric and magnetic field energies in the domain with the given // index. @@ -242,7 +227,7 @@ class PostOperator return measurement_cache.lumped_port_capacitor_energy; } - // Postprocess the S-parameter for recieving lumped or wave port index using the electric + // Postprocess the S-parameter for receiving lumped or wave port index using the electric // field solution. // TODO: In multi-excitation PR we will guarantee that lumped & wave ports have unique idx // TODO: Merge lumped and wave port S_ij calculations to allow both at same time. @@ -279,10 +264,10 @@ class PostOperator // the internal grid functions are real-valued, the returned fields have only nonzero real // parts. Output vectors are ordered by vector dimension, that is [v1x, v1y, v1z, v2x, // v2y, v2z, ...]. - int GetInterpolationOpVDim() const { return interp_op.GetVDim(); } const auto &GetProbes() const { return interp_op.GetProbes(); } std::vector> ProbeEField() const; std::vector> ProbeBField() const; + int GetInterpolationOpVDim() const { return interp_op.GetVDim(); } // Get the associated MPI communicator. MPI_Comm GetComm() const diff --git a/palace/utils/tablecsv.hpp b/palace/utils/tablecsv.hpp index f99bd3df3..0e173facd 100644 --- a/palace/utils/tablecsv.hpp +++ b/palace/utils/tablecsv.hpp @@ -102,7 +102,7 @@ class Column class Table { // Column-wise mini-table for storing data and and printing to csv file for doubles. - // Future: allow int and other output, allow non-owning memeory via span + // Future: allow int and other output, allow non-owning memory via span std::vector cols; // Cache value to reserve vector space by default