Skip to content

Commit a7c40fb

Browse files
committed
matrix view for markers
1 parent 5d13417 commit a7c40fb

10 files changed

Lines changed: 230 additions & 175 deletions

File tree

Lines changed: 92 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*!
22
* \file CPyWrapperMatrixView.hpp
3-
* \brief A simple matrix view to use with the python wrapper.
3+
* \brief Simple matrix views to use with the python wrapper.
44
* \author P. Gomes
55
* \version 7.5.1 "Blackbird"
66
*
@@ -27,28 +27,67 @@
2727

2828
#pragma once
2929

30+
#include <string>
3031
#include <utility>
3132
#include <vector>
32-
#include <string>
3333

34-
#include "C2DContainer.hpp"
34+
#include "../geometry/dual_grid/CVertex.hpp"
3535
#include "../parallelization/mpi_structure.hpp"
36+
#include "C2DContainer.hpp"
37+
38+
/*!
39+
* \brief Python wrapper matrix interface
40+
* The accessors in this macro provide a passive double interface to matrix of
41+
* su2double. This can be extended to allow access to derivative information.
42+
* Classes that use this macro encapsulate the access to the raw data (su2double)
43+
* via the functions "Access(row, col) -> su2double&" (const and non-const versions).
44+
* We use a macro because it is diffult to use modern C++ idioms (e.g. CRTP) with
45+
* SWIG. In addition to "Access" classes must have member variables "rows_", "cols_",
46+
* and "read_only_".
47+
*/
48+
#define PY_WRAPPER_MATRIX_INTERFACE \
49+
/*! \brief Returns the shape of the matrix. */ \
50+
std::pair<unsigned long, unsigned long> Shape() const { return std::make_pair(rows_, cols_); } \
51+
\
52+
/*! \brief Returns whether the data is read-only [true] or if it can be modified [false]. */ \
53+
bool IsReadOnly() const { return read_only_; } \
54+
\
55+
/*! \brief Gets the value for a (row, column) pair. */ \
56+
passivedouble operator()(unsigned long row, unsigned long col) const { return Get(row, col); } \
57+
\
58+
/*! \brief Gets the value for a (row, column) pair. */ \
59+
passivedouble Get(unsigned long row, unsigned long col) const { return SU2_TYPE::GetValue(Access(row, col)); } \
60+
\
61+
/*! \brief Gets the values for a row of the matrix. */ \
62+
std::vector<passivedouble> Get(unsigned long row) const { \
63+
std::vector<passivedouble> vals(cols_); \
64+
for (unsigned long j = 0; j < cols_; ++j) vals[j] = Get(row, j); \
65+
return vals; \
66+
} \
67+
/*! \brief Sets the value for a (row, column) pair. This clears derivative information. */ \
68+
void Set(unsigned long row, unsigned long col, passivedouble val) { Access(row, col) = val; } \
69+
\
70+
/*! \brief Sets the values for a row of the matrix. */ \
71+
void Set(unsigned long row, std::vector<passivedouble> vals) { \
72+
unsigned long j = 0; \
73+
for (const auto& val : vals) Set(row, j++, val); \
74+
}
3675

3776
/*!
3877
* \class CPyWrapperMatrixView
3978
* \ingroup PySU2
40-
* \brief A simple matrix view to use with the python wrapper. The accessors
41-
* in this class provide a passive double interface to su2activematrix.
42-
* This can be extended to allow access to derivative information of su2double.
79+
* \brief This class wraps su2activematrix for the python wrapper matrix interface.
80+
* It is generaly used to wrap access to solver variables defined for the entire volume.
4381
*/
4482
class CPyWrapperMatrixView {
45-
private:
83+
protected:
4684
static_assert(su2activematrix::IsRowMajor, "");
4785
su2double* data_ = nullptr;
4886
unsigned long rows_ = 0, cols_ = 0;
4987
std::string name_;
5088
bool read_only_ = false;
5189

90+
/*--- Define the functions required by the interface macro. ---*/
5291
inline const su2double& Access(unsigned long row, unsigned long col) const {
5392
if (row > rows_ || col > cols_) SU2_MPI::Error(name_ + " out of bounds", "CPyWrapperMatrixView");
5493
return data_[row * cols_ + col];
@@ -68,48 +107,59 @@ class CPyWrapperMatrixView {
68107
* \note "read_only" can be set to true to prevent the data from being modified.
69108
*/
70109
CPyWrapperMatrixView(su2activematrix& mat, const std::string& name, bool read_only)
71-
: data_(mat.data()), rows_(mat.rows()), cols_(mat.cols()), name_(name), read_only_(read_only) {}
72-
73-
/*!
74-
* \brief Returns the shape of the matrix.
75-
*/
76-
std::pair<unsigned long, unsigned long> Shape() const { return std::make_pair(rows_, cols_); }
77-
78-
/*!
79-
* \brief Returns whether the data is read-only [true] or if it can be modified [false].
80-
*/
81-
bool IsReadOnly() const { return read_only_; }
110+
: data_(mat.data()), rows_(mat.rows()), cols_(mat.cols()), name_(name), read_only_(read_only) {}
82111

83-
/*!
84-
* \brief Gets the value for a (row, column) pair.
85-
*/
86-
passivedouble operator() (unsigned long row, unsigned long col) const { return Get(row, col); }
112+
/*--- Use the macro to generate the interface. ---*/
113+
PY_WRAPPER_MATRIX_INTERFACE
114+
};
87115

88-
/*!
89-
* \brief Gets the value for a (row, column) pair.
90-
*/
91-
passivedouble Get(unsigned long row, unsigned long col) const { return SU2_TYPE::GetValue(Access(row, col)); }
116+
/*!
117+
* \class CPyWrapperMarkerMatrixView
118+
* \ingroup PySU2
119+
* \brief This class wraps su2activematrix for the python wrapper matrix interface restricting it
120+
* to the vertices of a given marker.
121+
*/
122+
class CPyWrapperMarkerMatrixView {
123+
private:
124+
static_assert(su2activematrix::IsRowMajor, "");
125+
su2double* data_ = nullptr;
126+
const CVertex* const* vertices_ = nullptr;
127+
unsigned long rows_ = 0, cols_ = 0;
128+
std::string name_;
129+
bool read_only_ = false;
92130

93-
/*!
94-
* \brief Gets the values for a row of the matrix.
95-
*/
96-
std::vector<passivedouble> Get(unsigned long row) const {
97-
std::vector<passivedouble> vals(cols_);
98-
for (unsigned long j = 0; j < cols_; ++j) vals[j] = Get(row, j);
99-
return vals;
131+
/*--- Define the functions required by the interface macro. ---*/
132+
inline const su2double& Access(unsigned long row, unsigned long col) const {
133+
if (row > rows_ || col > cols_) SU2_MPI::Error(name_ + " out of bounds", "CPyWrapperMarkerMatrixView");
134+
return data_[vertices_[row]->GetNode() * cols_ + col];
135+
}
136+
inline su2double& Access(unsigned long row, unsigned long col) {
137+
if (read_only_) SU2_MPI::Error(name_ + " is read-only", "CPyWrapperMarkerMatrixView");
138+
const auto& const_me = *this;
139+
return const_cast<su2double&>(const_me.Access(row, col));
100140
}
101141

102-
/*!
103-
* \brief Sets the value for a (row, column) pair.
104-
* \note This clears derivative information (consistently with C++ operator= with passive rhs).
105-
*/
106-
void Set(unsigned long row, unsigned long col, passivedouble val) { Access(row, col) = val; }
142+
public:
143+
CPyWrapperMarkerMatrixView() = default;
107144

108145
/*!
109-
* \brief Sets the values for a row of the matrix.
146+
* \brief Construct the view of the matrix.
147+
* \note "name" should be set to the variable name being returned to give better information to users.
148+
* \note "read_only" can be set to true to prevent the data from being modified.
110149
*/
111-
void Set(unsigned long row, std::vector<passivedouble> vals) {
112-
unsigned long j = 0;
113-
for (const auto& val : vals) Set(row, j++, val);
150+
CPyWrapperMarkerMatrixView(su2activematrix& mat, const CVertex* const* vertices, unsigned long n_vertices,
151+
const std::string& name, bool read_only)
152+
: data_(mat.data()),
153+
vertices_(vertices),
154+
rows_(n_vertices),
155+
cols_(mat.cols()),
156+
name_(name),
157+
read_only_(read_only) {
158+
if (mat.rows() < n_vertices) {
159+
SU2_MPI::Error(name + " has fewer rows than the number of vertices in the marker.", "CPyWrapperMarkerMatrixView");
160+
}
114161
}
162+
163+
/*--- Use the macro to generate the interface. ---*/
164+
PY_WRAPPER_MATRIX_INTERFACE
115165
};

SU2_CFD/include/drivers/CDriver.hpp

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -457,19 +457,19 @@ class CDriver : public CDriverBase {
457457
* \brief Get the number of external iterations.
458458
* \return Number of external iterations.
459459
*/
460-
unsigned long GetnTimeIter() const;
460+
unsigned long GetNumberTimeIter() const;
461461

462462
/*!
463463
* \brief Get the current external iteration.
464464
* \return Current external iteration.
465465
*/
466-
unsigned long GetTime_Iter() const;
466+
unsigned long GetTimeIter() const;
467467

468468
/*!
469469
* \brief Get the unsteady time step.
470470
* \return Unsteady time step.
471471
*/
472-
passivedouble GetUnsteady_TimeStep() const;
472+
passivedouble GetUnsteadyTimeStep() const;
473473

474474
/*!
475475
* \brief Get the name of the output file for the surface.
@@ -564,30 +564,6 @@ class CDriver : public CDriverBase {
564564
void SetFEA_Loads(unsigned short iMarker, unsigned long iVertex, passivedouble LoadX, passivedouble LoadY,
565565
passivedouble LoadZ);
566566

567-
/*!
568-
* \brief Return the displacements from the FEA solver.
569-
* \param[in] iMarker - Marker identifier.
570-
* \param[in] iVertex - Vertex identifier.
571-
* \return Vector of displacements.
572-
*/
573-
vector<passivedouble> GetFEA_Displacements(unsigned short iMarker, unsigned long iVertex) const;
574-
575-
/*!
576-
* \brief Return the velocities from the FEA Solver.
577-
* \param[in] iMarker - Marker identifier.
578-
* \param[in] iVertex - Vertex identifier.
579-
* \return Vector of velocities.
580-
*/
581-
vector<passivedouble> GetFEA_Velocity(unsigned short iMarker, unsigned long iVertex) const;
582-
583-
/*!
584-
* \brief Return the velocities from the FEA Solver.
585-
* \param[in] iMarker - Marker identifier.
586-
* \param[in] iVertex - Vertex identifier.
587-
* \return Vector of velocities at time n.
588-
*/
589-
vector<passivedouble> GetFEA_Velocity_n(unsigned short iMarker, unsigned long iVertex) const;
590-
591567
/*!
592568
* \brief Get the sensitivity of the flow loads for the structural solver.
593569
* \param[in] iMarker - Marker identifier.

SU2_CFD/include/drivers/CDriverBase.hpp

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#pragma once
2929

30+
#include <limits>
3031
#include "../../../Common/include/CConfig.hpp"
3132
#include "../../../Common/include/containers/CPyWrapperMatrixView.hpp"
3233
#include "../numerics/CNumerics.hpp"
@@ -200,6 +201,21 @@ class CDriverBase {
200201
return CPyWrapperMatrixView(*coords, "InitialCoordinates", true);
201202
}
202203

204+
/*!
205+
* \brief Get a read-only view of the initial (undeformed) coordinates of the mesh nodes of a marker.
206+
*/
207+
inline CPyWrapperMarkerMatrixView MarkerInitialCoordinates(unsigned short iMarker) const {
208+
if (!main_config->GetDeform_Mesh()) {
209+
SU2_MPI::Error("Initial coordinates are only available with DEFORM_MESH= YES", CURRENT_FUNCTION);
210+
}
211+
if (iMarker >= GetNumberMarkers()) SU2_MPI::Error("Marker index exceeds size.", CURRENT_FUNCTION);
212+
213+
auto* coords =
214+
const_cast<su2activematrix*>(solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetMesh_Coord());
215+
return CPyWrapperMarkerMatrixView(*coords, main_geometry->vertex[iMarker], main_geometry->GetnVertex(iMarker),
216+
"MarkerInitialCoordinates", true);
217+
}
218+
203219
/*!
204220
* \brief Get a read/write view of the current coordinates of all mesh nodes.
205221
*/
@@ -208,6 +224,16 @@ class CDriverBase {
208224
return CPyWrapperMatrixView(coords, "Coordinates", false);
209225
}
210226

227+
/*!
228+
* \brief Get a read/write view of the current coordinates of the mesh nodes of a marker.
229+
*/
230+
inline CPyWrapperMarkerMatrixView MarkerCoordinates(unsigned short iMarker) {
231+
if (iMarker >= GetNumberMarkers()) SU2_MPI::Error("Marker index exceeds size.", CURRENT_FUNCTION);
232+
auto& coords = const_cast<su2activematrix&>(main_geometry->nodes->GetCoord());
233+
return CPyWrapperMarkerMatrixView(coords, main_geometry->vertex[iMarker], main_geometry->GetnVertex(iMarker),
234+
"MarkerCoordinates", false);
235+
}
236+
211237
/*!
212238
* \brief Get the number of markers in the mesh.
213239
* \return Number of markers.
@@ -328,14 +354,47 @@ class CDriverBase {
328354
*/
329355
map<string, unsigned short> GetSolverIndices() const;
330356

357+
/*!
358+
* \brief Get the structural solver solution variable names with their associated indices.
359+
* These correspond to the column indices in the matrix returned by e.g. Solution().
360+
*/
361+
map<string, unsigned short> GetFEASolutionIndices() const;
362+
331363
/*!
332364
* \brief Get a read/write view of the current solution on all mesh nodes of a solver.
333365
*/
334366
inline CPyWrapperMatrixView Solution(unsigned short iSolver) {
335-
auto* solver = solver_container[ZONE_0][INST_0][MESH_0][iSolver];
336-
if (solver == nullptr) SU2_MPI::Error("The selected solver does not exist.", CURRENT_FUNCTION);
337-
auto& solution = solver->GetNodes()->GetSolution();
338-
return CPyWrapperMatrixView(solution, "Solution of " + solver->GetSolverName(), false);
367+
auto* solver = GetSolverAndCheckMarker(iSolver);
368+
return CPyWrapperMatrixView(solver->GetNodes()->GetSolution(), "Solution of " + solver->GetSolverName(), false);
369+
}
370+
371+
/*!
372+
* \brief Get a read/write view of the current solution on the mesh nodes of a marker.
373+
*/
374+
inline CPyWrapperMarkerMatrixView MarkerSolution(unsigned short iSolver, unsigned short iMarker) {
375+
auto* solver = GetSolverAndCheckMarker(iSolver, iMarker);
376+
return CPyWrapperMarkerMatrixView(
377+
solver->GetNodes()->GetSolution(), main_geometry->vertex[iMarker], main_geometry->GetnVertex(iMarker),
378+
"MarkerSolution of " + solver->GetSolverName(), false);
379+
}
380+
381+
/*!
382+
* \brief Get a read/write view of the solution at time N on all mesh nodes of a solver.
383+
*/
384+
inline CPyWrapperMatrixView SolutionTimeN(unsigned short iSolver) {
385+
auto* solver = GetSolverAndCheckMarker(iSolver);
386+
return CPyWrapperMatrixView(
387+
solver->GetNodes()->GetSolution_time_n(), "SolutionTimeN of " + solver->GetSolverName(), false);
388+
}
389+
390+
/*!
391+
* \brief Get a read/write view of the solution at time N on the mesh nodes of a marker.
392+
*/
393+
inline CPyWrapperMarkerMatrixView MarkerSolutionTimeN(unsigned short iSolver, unsigned short iMarker) {
394+
auto* solver = GetSolverAndCheckMarker(iSolver, iMarker);
395+
return CPyWrapperMarkerMatrixView(
396+
solver->GetNodes()->GetSolution_time_n(), main_geometry->vertex[iMarker], main_geometry->GetnVertex(iMarker),
397+
"MarkerSolutionTimeN of " + solver->GetSolverName(), false);
339398
}
340399

341400
/*!
@@ -349,15 +408,36 @@ class CDriverBase {
349408
* \warning Primitive variables are only available for flow solvers.
350409
*/
351410
inline CPyWrapperMatrixView Primitives() {
352-
auto* solver = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL];
353-
if (solver == nullptr) SU2_MPI::Error("The flow solver does not exist.", CURRENT_FUNCTION);
354-
auto& primitives = const_cast<su2activematrix&>(solver->GetNodes()->GetPrimitive());
355-
return CPyWrapperMatrixView(primitives, "Primitives", false);
411+
auto* solver = GetSolverAndCheckMarker(FLOW_SOL);
412+
return CPyWrapperMatrixView(const_cast<su2activematrix&>(solver->GetNodes()->GetPrimitive()), "Primitives", false);
356413
}
357414

415+
/*!
416+
* \brief Get a read/write view of the current primitive variables on the mesh nodes of a marker.
417+
* \warning Primitive variables are only available for flow solvers.
418+
*/
419+
inline CPyWrapperMarkerMatrixView MarkerPrimitives(unsigned short iMarker) {
420+
auto* solver = GetSolverAndCheckMarker(FLOW_SOL, iMarker);
421+
return CPyWrapperMarkerMatrixView(
422+
const_cast<su2activematrix&>(solver->GetNodes()->GetPrimitive()), main_geometry->vertex[iMarker],
423+
main_geometry->GetnVertex(iMarker), "MarkerPrimitives", false);
424+
}
358425
/// \}
359426

360427
protected:
428+
/*!
429+
* \brief Automates some boilerplate of accessing solution fields for the python wrapper.
430+
*/
431+
inline CSolver* GetSolverAndCheckMarker(unsigned short iSolver,
432+
unsigned short iMarker = std::numeric_limits<unsigned short>::max()) {
433+
if (iMarker < std::numeric_limits<unsigned short>::max() && iMarker > GetNumberMarkers()) {
434+
SU2_MPI::Error("Marker index exceeds size.", CURRENT_FUNCTION);
435+
}
436+
auto* solver = solver_container[ZONE_0][INST_0][MESH_0][iSolver];
437+
if (solver == nullptr) SU2_MPI::Error("The selected solver does not exist.", CURRENT_FUNCTION);
438+
return solver;
439+
}
440+
361441
/*!
362442
* \brief Initialize containers.
363443
*/

0 commit comments

Comments
 (0)