-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add postprocessing of lumped port boundaries to eigenmode simulations #129
Conversation
b55057f
to
3d2c39f
Compare
@@ -428,6 +432,8 @@ void BaseSolver::PostprocessProbes(const PostOperator &postop, const std::string | |||
i++; | |||
} | |||
const std::string F = (f == 0) ? "E" : "B"; | |||
const std::string unit = (f == 0) ? "(C/m²)" : "(Wb/m²)"; | |||
const auto type = (f == 0) ? IoData::ValueType::FIELD_E : IoData::ValueType::FIELD_B; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: Given f
is only being used for f==0
inside the loop, could use something like for (auto type : {IoData::ValueType::FIELD_E, IoData::ValueType::FIELD_B})
as the loop variable, and check off that directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, could do that too. Doesn't matter either way and will leave as is.
docs/src/guide/postprocessing.md
Outdated
@@ -14,6 +14,10 @@ element parameters. In addition, each simulation type will write a file called | |||
as well as lumped element energies, for each step of the simulation (eigenmode, frequency, | |||
or time step, for examples). | |||
|
|||
Models containing ports lumped or wave port boundaries or surface current excitations will |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lumped ports rather than ports lumped?
each step of the simulation (eigenmode, frequency, or time step) are written to ASCII files | ||
named `port-V.csv` and `port-I.csv`, respectively. These files also include the excitation | ||
voltage and current corresponding to the incident wave on excited port boundaries. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the "Additionally" this seems like it should be in the previous paragraph?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's fine as is, separated to emphasize ports vs. surface currents.
docs/src/guide/problem.md
Outdated
the directory specified by [`config["Problem"]["Output"]`] | ||
(../config/problem.md#config["Problem"]). Additionally, surface current excitation time | ||
histories are written to `surface-I.csv`. | ||
As for the frequency domain driven case, postprocessing of quantities related to ports is |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: Postprocessing of quantities related to ports for the frequency domain driven case is described in the sections...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change would not be correct and would change the meaning of the sentence. This is referring to time domain port processing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then it would be "As with"? As for is describing the frequency domain, as with is drawing similarity to the frequency domain case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I'll change to "As with"
and you can count it as a win for the grammar police.
Mpi::Print(" Field energy E ({:.3e}) + H ({:.3e}) = {:.3e}\n", E_elec, E_mag, | ||
E_elec + E_mag); | ||
Mpi::Print(" Field energy E ({:.3e} J) + H ({:.3e} J) = {:.3e} J\n", E_elec * J, | ||
E_mag * J, (E_elec + E_mag) * J); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other places (basesolver.cpp
) there's a call to iodata.DimensionalizeValue
, vs constructing the conversion constant like this. I guess this was done elsewhere because of the clang-format off
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't really matter, usually use the constant to avoid many repeated calls to DimensionalizeValue
but it's a choice without much difference either way.
palace/drivers/basesolver.cpp
Outdated
@@ -428,6 +432,8 @@ void BaseSolver::PostprocessProbes(const PostOperator &postop, const std::string | |||
i++; | |||
} | |||
const std::string F = (f == 0) ? "E" : "B"; | |||
const std::string unit = (f == 0) ? "(C/m²)" : "(Wb/m²)"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These units don't match those from IoData::DimensionalizeValue
, where ValueType::FIELD_E
is [V/m] and ValueType::FIELD_B
is [Wb/m²]
. Which is correct or am I missing a unit conversion here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, should be V/m for E. Was distracted doing units of B instead of H and so wrote units for D instead of E. Good catch.
} | ||
return v * sf; | ||
} | ||
|
||
template double IoData::DimensionalizeValue(IoData::ValueType, double) const; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the explicit instantiation of only the double
case and this being in a cpp, why the template? I'm guessing that complex was going to be an option originally?
@@ -556,10 +556,13 @@ void IoData::NondimensionalizeInputs(mfem::ParMesh &mesh) | |||
Lc, tc); | |||
} | |||
|
|||
double IoData::DimensionalizeValue(IoData::ValueType type, double v) const | |||
template <typename T> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this is a free function, could probably be marked constexpr
if std::sqrt
was. I'm assuming that there's some compilers we use that don't support that though, which is preventing that change? Would make the cases with the fixed conversion constants possible to be constexpr
too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::sqrt
is not always constexpr
and you don't gain much (anything) here from this being constexpr
. Fine as is.
template <typename T> | ||
T DimensionalizeValue(ValueType type, T v) const; | ||
template <typename T> | ||
std::complex<T> DimensionalizeValue(ValueType type, std::complex<T> v) const | ||
{ | ||
return {DimensionalizeValue(type, v.real()), DimensionalizeValue(type, v.imag())}; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the templates here can all be removed for double
given the base case is only instantiated for double
in the cpp. I believe if you passed DimensionalizeValue(type, 1);
with this, it would compile and then linker error, whereas with explicit double
it would perform the implicit conversion which is what would be wanted. If the goal is to support variable precision, I think that should be done in another pr upgrading all the usages of double
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commenting here along with #129 (comment), but yes originally I had templated for complex but then decided on this design being nicer. I don't see any penalty for it being templated, so will keep it. If someone is converting an integral type they can add an explicit instantiation when they come upon the linker error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function doesn't however work for other types because all the constants in electromagnetics
are double. Adding an explicit instantiation for int
for instance gives
const auto f1 = iodata.DimensionalizeValue(IoData::ValueType::FREQUENCY, 1.0);
const auto f2 = iodata.DimensionalizeValue(IoData::ValueType::FREQUENCY, 1);
std::cout << "f1 " << f1 << " f2 " << f2 << std::endl;
prints f1 0.870683 f2 0
due to the rules on integer multiplication/division and casting. Dropping the template for double
performs the conversions and gives f1 0.870683 f2 0.870683
as expected. The extra template syntax buys unexpected behaviour, or requires a user to exercise extra care on numeric types, neither seems ideal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK maybe it was a bad quick example, you'd never want to instantiate this function for an int
and if you did then the output you are getting is actually exactly what you'd expect and I argue is actually correct behavior (the returned type should be integral, not floating point in this case). I have a hard time seeing where developers will not be able to take the care to work with the function as it currently exists.
output.print("{:+{}.{}e},{:+{}.{}e}{}", | ||
data.Vi.real(), table.w, table.p, | ||
data.Vi.imag(), table.w, table.p, | ||
(data.idx == port_data.back().idx) ? "" : ","); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are no repeated port indices correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right, but this is a check to skip the comma at the last iteration of the loop.
… and correct redimensionalization of voltages (V), currents (I) for output
3d2c39f
to
5198e05
Compare
77d0715
to
e313a33
Compare
e313a33
to
59bd14f
Compare
@hughcars, any final comments here that need to be addressed before approval? |
These quantities can be useful in addition to the EPR output for characterizing multi-port systems along with the computed pole locations.
This PR also updates the output of various computed quantities like energies, voltages, currents, and field values to be dimensional based on a choice for
H0
, the characteristic magnetic field strength used for nondimensionalization (see https://awslabs.github.io/palace/stable/reference/). In particular, we chooseH0
so that the unit power incident on ports for driven simulations corresponds to 1 W. The fields written for ParaView visualization are NOT redimensionalized, however. They can be if this would be useful, but for now we leave them nondimensional since they are only used for visualization.Resolves #123.