2525 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
2626 */
2727
28+ #include < sstream>
2829#include < string>
2930
3031#include " ../../include/output/CFlowOutput.hpp"
@@ -765,16 +766,42 @@ void CFlowOutput::SetCustomOutputs(const CSolver* const* solver, const CGeometry
765766 } else {
766767 SU2_MPI::Error (" Unknown flow solver type." , CURRENT_FUNCTION);
767768 }
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 ;
769+ /* --- Convert marker names to their index (if any) in this rank. Or probe locations to nearest points. ---*/
770+
771+ if (output.type != OperationType::PROBE) {
772+ output.markerIndices .clear ();
773+ for (const auto & marker : output.markers ) {
774+ for (auto iMarker = 0u ; iMarker < config->GetnMarker_All (); ++iMarker) {
775+ if (config->GetMarker_All_TagBound (iMarker) == marker) {
776+ output.markerIndices .push_back (iMarker);
777+ continue ;
778+ }
779+ }
780+ }
781+ } else {
782+ if (output.markers .size () != nDim) {
783+ SU2_MPI::Error (" Wrong number of coordinates to specify probe " + output.name , CURRENT_FUNCTION);
784+ }
785+ su2double coord[3 ] = {};
786+ for (auto iDim = 0u ; iDim < nDim; ++iDim) coord[iDim] = std::stod (output.markers [iDim]);
787+ su2double minDist = std::numeric_limits<su2double>::max ();
788+ unsigned long minPoint = 0 ;
789+ for (auto iPoint = 0ul ; iPoint < geometry->GetnPointDomain (); ++iPoint) {
790+ const su2double dist = GeometryToolbox::SquaredDistance (nDim, coord, geometry->nodes ->GetCoord (iPoint));
791+ if (dist < minDist) {
792+ minDist = dist;
793+ minPoint = iPoint;
776794 }
777795 }
796+ /* --- Decide which rank owns the probe. ---*/
797+ su2double globMinDist;
798+ SU2_MPI::Allreduce (&minDist, &globMinDist, 1 , MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm ());
799+ output.iPoint = fabs (minDist - globMinDist) < EPS ? minPoint : CustomOutput::PROBE_NOT_OWNED;
800+ if (output.iPoint != CustomOutput::PROBE_NOT_OWNED) {
801+ std::cout << " Probe " << output.name << " is using global point "
802+ << geometry->nodes ->GetGlobalIndex (output.iPoint )
803+ << " , distance from target location is " << sqrt (minDist) << std::endl;
804+ }
778805 }
779806 }
780807
@@ -787,6 +814,37 @@ void CFlowOutput::SetCustomOutputs(const CSolver* const* solver, const CGeometry
787814 continue ;
788815 }
789816
817+ /* --- Prepares the functor that maps symbol indices to values at a given point
818+ * (see ConvertVariableSymbolsToIndices). ---*/
819+
820+ auto MakeFunctor = [&](unsigned long iPoint) {
821+ /* --- This returns another lambda that captures iPoint by value. ---*/
822+ return [&, iPoint](unsigned long i) {
823+ if (i < CustomOutput::NOT_A_VARIABLE) {
824+ const auto solIdx = i / CustomOutput::MAX_VARS_PER_SOLVER;
825+ const auto varIdx = i % CustomOutput::MAX_VARS_PER_SOLVER;
826+ if (solIdx == FLOW_SOL) {
827+ return flowNodes->GetPrimitive (iPoint, varIdx);
828+ } else {
829+ return solver[solIdx]->GetNodes ()->GetSolution (iPoint, varIdx);
830+ }
831+ } else {
832+ return *output.otherOutputs [i - CustomOutput::NOT_A_VARIABLE];
833+ }
834+ };
835+ };
836+
837+ if (output.type == OperationType::PROBE) {
838+ su2double value = std::numeric_limits<su2double>::max ();
839+ if (output.iPoint != CustomOutput::PROBE_NOT_OWNED) {
840+ value = output.eval (MakeFunctor (output.iPoint ));
841+ }
842+ su2double tmp = value;
843+ SU2_MPI::Allreduce (&tmp, &value, 1 , MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm ());
844+ SetHistoryOutputValue (output.name , value);
845+ continue ;
846+ }
847+
790848 /* --- Surface integral of the expression. ---*/
791849
792850 std::array<su2double, 2 > integral = {0.0 , 0.0 };
@@ -812,23 +870,7 @@ void CFlowOutput::SetCustomOutputs(const CSolver* const* solver, const CGeometry
812870 }
813871 weight *= GetAxiFactor (axisymmetric, *geometry->nodes , iPoint, iMarker);
814872 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);
873+ local_integral[0 ] += weight * output.eval (MakeFunctor (iPoint));
832874 }
833875 END_SU2_OMP_FOR
834876 }
0 commit comments