Skip to content

Commit 7245e86

Browse files
committed
nearest point probes
1 parent 12e0ed9 commit 7245e86

5 files changed

Lines changed: 71 additions & 29 deletions

File tree

SU2_CFD/include/output/COutput.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ class COutput {
187187
CustomHistoryOutput customObjFunc; /*!< \brief User-defined expression for a custom objective. */
188188

189189
/*! \brief Type of operation for custom outputs. */
190-
enum class OperationType { MACRO, FUNCTION, AREA_AVG, AREA_INT, MASSFLOW_AVG, MASSFLOW_INT };
190+
enum class OperationType { MACRO, FUNCTION, AREA_AVG, AREA_INT, MASSFLOW_AVG, MASSFLOW_INT, PROBE };
191191

192192
/*! \brief Struct to hold a parsed custom output function. */
193193
struct CustomOutput {
@@ -201,6 +201,9 @@ class COutput {
201201
mel::ExpressionTree<passivedouble> expression;
202202
std::vector<std::string> varSymbols;
203203
std::vector<unsigned short> markerIndices;
204+
static constexpr long PROBE_NOT_SETUP = -2;
205+
static constexpr long PROBE_NOT_OWNED = -1;
206+
long iPoint = PROBE_NOT_SETUP;
204207

205208
/*--- The symbols (strings) are associated with an integer index for efficiency. For evaluation this index
206209
is passed to a functor that returns the value associated with the symbol. This functor is an input to "eval()"

SU2_CFD/src/output/CFlowOutput.cpp

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -765,16 +765,37 @@ void CFlowOutput::SetCustomOutputs(const CSolver* const* solver, const CGeometry
765765
} else {
766766
SU2_MPI::Error("Unknown flow solver type.", CURRENT_FUNCTION);
767767
}
768-
/*--- Convert marker names to their index (if any) in this rank. ---*/
769-
770-
output.markerIndices.clear();
771-
for (const auto& marker : output.markers) {
772-
for (auto iMarker = 0u; iMarker < config->GetnMarker_All(); ++iMarker) {
773-
if (config->GetMarker_All_TagBound(iMarker) == marker) {
774-
output.markerIndices.push_back(iMarker);
775-
continue;
768+
/*--- Convert marker names to their index (if any) in this rank. Or probe locations to nearest points. ---*/
769+
770+
if (output.type != OperationType::PROBE) {
771+
output.markerIndices.clear();
772+
for (const auto& marker : output.markers) {
773+
for (auto iMarker = 0u; iMarker < config->GetnMarker_All(); ++iMarker) {
774+
if (config->GetMarker_All_TagBound(iMarker) == marker) {
775+
output.markerIndices.push_back(iMarker);
776+
continue;
777+
}
778+
}
779+
}
780+
} else {
781+
if (output.markers.size() != nDim) {
782+
SU2_MPI::Error("Wrong number of coordinates to specify probe " + output.name, CURRENT_FUNCTION);
783+
}
784+
su2double coord[3] = {};
785+
for (auto iDim = 0u; iDim < nDim; ++iDim) coord[iDim] = std::stod(output.markers[iDim]);
786+
su2double minDist = std::numeric_limits<su2double>::max();
787+
unsigned long minPoint = 0;
788+
for (auto iPoint = 0ul; iPoint < geometry->GetnPointDomain(); ++iPoint) {
789+
const su2double dist = GeometryToolbox::SquaredDistance(nDim, coord, geometry->nodes->GetCoord(iPoint));
790+
if (dist < minDist) {
791+
minDist = dist;
792+
minPoint = iPoint;
776793
}
777794
}
795+
/*--- Decide which rank owns the probe. ---*/
796+
su2double globMinDist;
797+
SU2_MPI::Allreduce(&minDist, &globMinDist, 1, MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm());
798+
output.iPoint = (minDist == globMinDist) ? minPoint : CustomOutput::PROBE_NOT_OWNED;
778799
}
779800
}
780801

@@ -787,6 +808,36 @@ void CFlowOutput::SetCustomOutputs(const CSolver* const* solver, const CGeometry
787808
continue;
788809
}
789810

811+
/*--- Prepares the functor that maps symbol indices to values at a given point
812+
* (see ConvertVariableSymbolsToIndices). ---*/
813+
814+
auto MakeFunctor = [&](unsigned long iPoint) {
815+
return [&, iPoint](unsigned long i) {
816+
if (i < CustomOutput::NOT_A_VARIABLE) {
817+
const auto solIdx = i / CustomOutput::MAX_VARS_PER_SOLVER;
818+
const auto varIdx = i % CustomOutput::MAX_VARS_PER_SOLVER;
819+
if (solIdx == FLOW_SOL) {
820+
return flowNodes->GetPrimitive(iPoint, varIdx);
821+
} else {
822+
return solver[solIdx]->GetNodes()->GetSolution(iPoint, varIdx);
823+
}
824+
} else {
825+
return *output.otherOutputs[i - CustomOutput::NOT_A_VARIABLE];
826+
}
827+
};
828+
};
829+
830+
if (output.type == OperationType::PROBE) {
831+
su2double value = std::numeric_limits<su2double>::max();
832+
if (output.iPoint != CustomOutput::PROBE_NOT_OWNED) {
833+
value = output.eval(MakeFunctor(output.iPoint));
834+
}
835+
su2double tmp = value;
836+
SU2_MPI::Allreduce(&tmp, &value, 1, MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm());
837+
SetHistoryOutputValue(output.name, value);
838+
continue;
839+
}
840+
790841
/*--- Surface integral of the expression. ---*/
791842

792843
std::array<su2double, 2> integral = {0.0, 0.0};
@@ -812,23 +863,7 @@ void CFlowOutput::SetCustomOutputs(const CSolver* const* solver, const CGeometry
812863
}
813864
weight *= GetAxiFactor(axisymmetric, *geometry->nodes, iPoint, iMarker);
814865
local_integral[1] += weight;
815-
816-
/*--- Prepare the functor that maps symbol indices to values (see ConvertVariableSymbolsToIndices). ---*/
817-
818-
auto Functor = [&](unsigned long i) {
819-
if (i < CustomOutput::NOT_A_VARIABLE) {
820-
const auto solIdx = i / CustomOutput::MAX_VARS_PER_SOLVER;
821-
const auto varIdx = i % CustomOutput::MAX_VARS_PER_SOLVER;
822-
if (solIdx == FLOW_SOL) {
823-
return flowNodes->GetPrimitive(iPoint, varIdx);
824-
} else {
825-
return solver[solIdx]->GetNodes()->GetSolution(iPoint, varIdx);
826-
}
827-
} else {
828-
return *output.otherOutputs[i - CustomOutput::NOT_A_VARIABLE];
829-
}
830-
};
831-
local_integral[0] += weight * output.eval(Functor);
866+
local_integral[0] += weight * output.eval(MakeFunctor(iPoint));
832867
}
833868
END_SU2_OMP_FOR
834869
}

SU2_CFD/src/output/COutput.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2186,6 +2186,7 @@ void COutput::SetCustomOutputs(const CConfig* config) {
21862186
{"AreaInt", OperationType::AREA_INT},
21872187
{"MassFlowAvg", OperationType::MASSFLOW_AVG},
21882188
{"MassFlowInt", OperationType::MASSFLOW_INT},
2189+
{"Probe", OperationType::PROBE},
21892190
};
21902191
std::stringstream knownOps;
21912192
for (const auto& item : opMap) knownOps << item.first << ", ";

TestCases/parallel_regression.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ def main():
272272
flatplate_udobj.cfg_dir = "user_defined_functions"
273273
flatplate_udobj.cfg_file = "lam_flatplate.cfg"
274274
flatplate_udobj.test_iter = 20
275-
flatplate_udobj.test_vals = [-6.653802, -1.181430, -0.794887, 0.000611, -0.000369, 0.000736, -0.001104, 596.690000, 299.800000, 296.890000, 21.492000, 0.563990, 2.278700]
275+
flatplate_udobj.test_vals = [-6.653802, -1.181430, -0.794887, 0.000611, -0.000369, 0.000736, -0.001104, 596.690000, 299.800000, 296.890000, 21.492000, 0.563990, 36.131, 2.278700]
276276
test_list.append(flatplate_udobj)
277277

278278
# Laminar cylinder (steady)

TestCases/user_defined_functions/lam_flatplate.cfg

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,22 @@ RESTART_SOL= NO
2424
% - AreaAvg and AreaInt: Computes an area average or integral of a field (the
2525
% expression) over the list of markers.
2626
% - MassFlowAvg and MassFlowInt: Computes a mass flow average or integral.
27+
% - Probe: Evaluates the expression using the values of the mesh point closest
28+
% to the coordinates specified inside "[]", [x, y] or [x, y, z] (2 or 3D).
2729
% NOTE: Each custom output can only use one type, e.g. it is not possible to
2830
% write 'p_drop : AreaAvg{PRESSURE}[inlet] - AreaAvg{PRESSURE}[outlet]'. This
2931
% would need to be separated into two AreaAvg outputs and one Function to
3032
% compute their difference.
3133
CUSTOM_OUTPUTS= 'velocity : Macro{sqrt(pow(VELOCITY_X, 2) + pow(VELOCITY_Y, 2) + pow(VELOCITY_Z, 2))};\
3234
avg_vel : AreaAvg{$velocity}[z_minus, z_plus];\
3335
var_vel : AreaAvg{pow($velocity - avg_vel, 2)}[z_minus, z_plus];\
34-
dev_vel : Function{sqrt(var_vel) / avg_vel}'
36+
dev_vel : Function{sqrt(var_vel) / avg_vel};\
37+
probe1 : Probe{$velocity}[0.005, 0.005, 0.05]'
3538
%
3639
% "COMBO" is the name and group of the output for the objective function
3740
% (regardless of definition). "CUSTOM" is the group for all custom outpus.
3841
SCREEN_OUTPUT= INNER_ITER, RMS_DENSITY, RMS_ENERGY, LINSOL_RESIDUAL, FORCE_Z,\
39-
SURFACE_MASSFLOW, SURFACE_TOTAL_TEMPERATURE, avg_vel, dev_vel, COMBO
42+
SURFACE_MASSFLOW, SURFACE_TOTAL_TEMPERATURE, avg_vel, dev_vel, probe1, COMBO
4043
HISTORY_OUTPUT = ITER, AERO_COEFF, FLOW_COEFF, FLOW_COEFF_SURF, CUSTOM, COMBO
4144
OBJECTIVE_FUNCTION= CUSTOM_OBJFUNC
4245
% Here we define how the custom objective is computed from other outputs. For

0 commit comments

Comments
 (0)