Skip to content

Commit 4256c98

Browse files
committed
power iteration method
1 parent 86c0b98 commit 4256c98

File tree

3 files changed

+161
-3
lines changed

3 files changed

+161
-3
lines changed

SU2_CFD/include/drivers/CSinglezoneDriver.hpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,52 @@ class CSinglezoneDriver : public CDriver {
4646
* \return Boolean indicating whether the problem is converged.
4747
*/
4848
virtual bool GetTimeConvergence() const;
49+
vector<passivedouble> v_estimate;
50+
51+
/*!
52+
* \brief Seed derivatives for all solvers in the zone.
53+
* \param[in] derivatives - Vector of derivative values
54+
*/
55+
void SeedAllDerivatives(const vector<passivedouble>& derivatives, CVariable* nodes, CGeometry *geometry) {
56+
unsigned long offset = 0;
57+
for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) {
58+
CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][iSol];
59+
if (!solver) continue;
60+
61+
unsigned short nVar = solver->GetnVar();
62+
unsigned long nPoint = geometry->GetnPointDomain();
63+
unsigned long nTotal = nVar * nPoint;
64+
65+
vector<passivedouble> solver_derivs(derivatives.begin() + offset,
66+
derivatives.begin() + offset + nTotal);
67+
solver->SetSolutionDerivatives(solver_derivs, nodes);
68+
offset += nTotal;
69+
}
70+
}
71+
72+
/*!
73+
* \brief Extract derivatives from all solvers in the zone.
74+
* \param[out] derivatives - Vector to store derivative values
75+
*/
76+
void GetAllDerivatives(vector<passivedouble>& derivatives, CVariable* nodes, CGeometry *geometry) {
77+
unsigned long offset = 0;
78+
for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) {
79+
CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][iSol];
80+
if (!solver) continue;
81+
82+
unsigned short nVar = solver->GetnVar();
83+
unsigned long nPoint = geometry->GetnPointDomain();
84+
unsigned long nTotal = nVar * nPoint;
85+
86+
vector<passivedouble> solver_derivs(nTotal);
87+
solver->GetSolutionDerivatives(solver_derivs, nodes);
88+
89+
for (unsigned long i = 0; i < nTotal; i++) {
90+
derivatives[offset + i] = solver_derivs[i];
91+
}
92+
offset += nTotal;
93+
}
94+
}
4995

5096
public:
5197

@@ -110,4 +156,10 @@ class CSinglezoneDriver : public CDriver {
110156
*/
111157
bool Monitor(unsigned long TimeIter) override;
112158

159+
/*!
160+
* \brief Calculate the spectral radius using power iteration method.
161+
*/
162+
void PreRunSpectralRadius();
163+
164+
void PostRunSpectralRadius();
113165
};

SU2_CFD/include/solvers/CSolver.hpp

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
#include "../../../Common/include/graph_coloring_structure.hpp"
5757
#include "../../../Common/include/toolboxes/MMS/CVerificationSolution.hpp"
5858
#include "../variables/CVariable.hpp"
59-
59+
// #include "../drivers/CDriver.hpp"
6060
#ifdef HAVE_LIBROM
6161
#include "librom.h"
6262
#endif
@@ -103,6 +103,9 @@ class CSolver {
103103
su2double Total_Custom_ObjFunc = 0.0; /*!< \brief Total custom objective function. */
104104
su2double Total_ComboObj = 0.0; /*!< \brief Total 'combo' objective for all monitored boundaries */
105105

106+
CSysVector<su2double> seed_vector; // Current eigenvector estimate
107+
su2double spectral_radius;
108+
106109
/*--- Variables that need to go. ---*/
107110

108111
su2double *Residual, /*!< \brief Auxiliary nVar vector. */
@@ -4352,6 +4355,34 @@ inline void CustomSourceResidual(CGeometry *geometry, CSolver **solver_container
43524355
AD::EndNoSharedReading();
43534356
}
43544357

4358+
/*!
4359+
* \brief Seed derivatives for all solution variables using a flat vector.
4360+
* \param[in] derivatives - Flat vector of derivative values (size nVar * nPoint)
4361+
*/
4362+
void SetSolutionDerivatives(const vector<passivedouble>& derivatives, CVariable* nodes) {
4363+
unsigned long offset = 0;
4364+
for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) {
4365+
su2double* solution = nodes->GetSolution(iPoint);
4366+
for (unsigned short iVar = 0; iVar < nVar; iVar++) {
4367+
SU2_TYPE::SetDerivative(solution[iVar], derivatives[offset++]);
4368+
}
4369+
}
4370+
}
4371+
4372+
/*!
4373+
* \brief Get derivatives from all solution variables into a flat vector.
4374+
* \param[out] derivatives - Flat vector to store derivative values (size nVar * nPoint)
4375+
*/
4376+
void GetSolutionDerivatives(vector<passivedouble>& derivatives, CVariable* nodes) const {
4377+
unsigned long offset = 0;
4378+
for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) {
4379+
su2double* solution = nodes->GetSolution(iPoint);
4380+
for (unsigned short iVar = 0; iVar < nVar; iVar++) {
4381+
derivatives[offset++] = SU2_TYPE::GetDerivative(solution[iVar]);
4382+
}
4383+
}
4384+
}
4385+
43554386
protected:
43564387
/*!
43574388
* \brief Allocate the memory for the verification solution, if necessary.

SU2_CFD/src/drivers/CSinglezoneDriver.cpp

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void CSinglezoneDriver::StartSolver() {
7373
Preprocess(TimeIter);
7474

7575
/*--- Run a time-step iteration of the single-zone problem. ---*/
76-
76+
PreRunSpectralRadius();
7777
Run();
7878

7979
/*--- Perform some postprocessing on the solution before the update ---*/
@@ -83,7 +83,7 @@ void CSinglezoneDriver::StartSolver() {
8383
/*--- Update the solution for dual time stepping strategy ---*/
8484

8585
Update();
86-
86+
PostRunSpectralRadius();
8787
/*--- Monitor the computations after each iteration. ---*/
8888

8989
Monitor(TimeIter);
@@ -312,3 +312,78 @@ bool CSinglezoneDriver::Monitor(unsigned long TimeIter){
312312
bool CSinglezoneDriver::GetTimeConvergence() const{
313313
return output_container[ZONE_0]->GetCauchyCorrectedTimeConvergence(config_container[ZONE_0]);
314314
}
315+
316+
void CSinglezoneDriver::PreRunSpectralRadius() {
317+
CGeometry* geometry = nullptr;
318+
CVariable* nodes = nullptr;
319+
320+
// Get total number of variables
321+
unsigned long nVarTotal = 0;
322+
unsigned long nPoint = geometry->GetnPointDomain();
323+
for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) {
324+
CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][iSol];
325+
if (solver) nVarTotal += solver->GetnVar();
326+
}
327+
328+
unsigned long nTotal = nVarTotal * nPoint;
329+
330+
// Initialize power iteration vector
331+
if (v_estimate.empty()) {
332+
v_estimate.resize(nTotal);
333+
passivedouble norm = 0.0;
334+
for (unsigned long i = 0; i < nTotal; i++) {
335+
v_estimate[i] = static_cast<passivedouble>(rand()) / RAND_MAX;
336+
norm += v_estimate[i] * v_estimate[i];
337+
}
338+
norm = sqrt(norm);
339+
for (unsigned long i = 0; i < nTotal; i++) v_estimate[i] /= norm;
340+
}
341+
342+
// Seed derivatives for all solvers
343+
SeedAllDerivatives(v_estimate, nodes, geometry);
344+
}
345+
346+
void CSinglezoneDriver::PostRunSpectralRadius() {
347+
CGeometry* geometry = nullptr;
348+
CVariable* nodes = nullptr;
349+
350+
// Get total number of variables (var*nodes)
351+
unsigned long nVarTotal = 0;
352+
unsigned long nPoint = geometry->GetnPointDomain();
353+
for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) {
354+
CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][iSol];
355+
if (solver) nVarTotal += solver->GetnVar();
356+
}
357+
unsigned long nTotal = nVarTotal * nPoint;
358+
359+
// Extract derivatives from all solvers
360+
vector<passivedouble> w(nTotal);
361+
GetAllDerivatives(w, nodes, geometry);
362+
363+
// Compute norm and update eigenvector estimate
364+
passivedouble rho_new = 0.0;
365+
for (unsigned long i = 0; i < nTotal; i++) rho_new += w[i] * w[i];
366+
rho_new = sqrt(rho_new);
367+
368+
for (unsigned long i = 0; i < nTotal; i++) v_estimate[i] = w[i] / rho_new;
369+
370+
// Check convergence
371+
static passivedouble rho_old = 0.0;
372+
static int iter = 0;
373+
374+
int max_iter = 500; //add config option later
375+
passivedouble tol = 1e-7; //add config option later
376+
377+
if (abs(rho_new - rho_old) < tol || iter >= max_iter) {
378+
if (rank == MASTER_NODE) {
379+
std::cout << "Spectral Radius Estimate: " << rho_new << " after " << iter << " iterations." << std::endl;
380+
}
381+
382+
rho_old = 0.0;
383+
iter = 0;
384+
v_estimate.clear();
385+
} else {
386+
rho_old = rho_new;
387+
iter++;
388+
}
389+
}

0 commit comments

Comments
 (0)