Loading...
Searching...
No Matches
27Online.C
1/*---------------------------------------------------------------------------*\
2 ██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗
3 ██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║
4 ██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║
5 ██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝
6 ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝
7 ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝
8
9 * In real Time Highly Advanced Computational Applications for Finite Volumes
10 * Copyright (C) 2017 by the ITHACA-FV authors
11-------------------------------------------------------------------------------
12License
13 This file is part of ITHACA-FV
14 ITHACA-FV is free software: you can redistribute it and/or modify
15 it under the terms of the GNU Lesser General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18 ITHACA-FV is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU Lesser General Public License for more details.
22 You should have received a copy of the GNU Lesser General Public License
23 along with ITHACA-FV. If not, see <http://www.gnu.org/licenses/>.
24Description
25 Example of the hyperreduction of the Smagorinsky term in a ROM
26SourceFiles
27 27SmagorinskyHyperreduction.C
28\*---------------------------------------------------------------------------*/
29
30#include "27Online.H"
31
32
33tutorial27_online::tutorial27_online(StoredParameters* parameters):
34 m_parameters(parameters),
35 m_UnsteadyNSTurb(new UnsteadyNSTurb(m_parameters)),
36 runTime2(Foam::Time::controlDictName, ".", m_parameters->get_casenameData()),
37 meanU(new volVectorField(m_parameters->get_meanU())),
38 nModesU(m_parameters->get_nModes()["U"]),
39 interpolatedField(m_parameters->get_DEIMInterpolatedField()),
40 nModesHR(m_parameters->get_nModes()[interpolatedField]),
41 nMagicPoints(m_parameters->get_nMagicPoints()),
42 magicPoints(m_parameters->get_magicPoints()),
43 localMagicPoints(m_parameters->get_localMagicPoints()),
44 Ck(m_parameters->get_Ck()),
45 Ce(m_parameters->get_Ce())
46{
47 ITHACAstream::read_fields(spatialModesU, "U", "./ITHACAoutput/spatialModes_" + std::to_string(nModesU) + "modes/");
48 massMatrixInv = ITHACAutilities::getMassMatrix(spatialModesU).completeOrthogonalDecomposition().pseudoInverse();
49 cnpy::load(temporalModesUSimulation, "./ITHACAoutput/temporalModesSimulation_" + std::to_string(nModesU) + "modes/U.npy");
50
51 weightAtMg = Eigen::VectorXd(nMagicPoints);
52 for (int i = 0; i < nMagicPoints; i++)
53 {
54 weightAtMg(i) = std::pow(m_parameters->get_submesh().V()[localMagicPoints[i]], 0.5);
55 }
56
57 if (ITHACAutilities::containsSubstring(interpolatedField, "fullStressFunction"))
58 {
59 d = 3;
60 meanSmagOnMagicNeighborhoods = new volVectorField(m_parameters->get_meanVectorDEIMMagic());
61 for (auto& defTensorOfMode:m_parameters->get_deformationTensorOfModesOnMagicNeighborhoods())
62 {
63 defTensorOfModesAtMg.push_back(defTensorOfMode);
64 }
65 }
66 else if (ITHACAutilities::containsSubstring(interpolatedField, "nut"))
67 {
68 d = 1;
69 meanNutOnMagicPoints = new volScalarField(m_parameters->get_meanScalarDEIMMagic());
70 for (auto& defTensorOfMode:m_parameters->get_deformationTensorOfModesOnMagicPoints())
71 {
72 defTensorOfModesAtMg.push_back(defTensorOfMode);
73 }
74 }
75
76 nut0 = new volScalarField("nut", volScalarField(
77 IOobject("nut0", m_parameters->get_casenameData() + "0", m_parameters->get_submesh(), IOobject::MUST_READ),
78 m_parameters->get_submesh()));
79
80 delta = new volScalarField(m_parameters->get_magicDelta());
81 aaa = new volScalarField(Ce/(*delta));
82 inv2aaa = new volScalarField(1/(2*(*aaa)));
83
84 fullDefField = new volTensorField(defTensorOfModesAtMg[0]);
85 bbb = new volScalarField((2.0/3.0)*tr(*fullDefField));
86 ccc = new volScalarField(2*Ck*(*delta)*(dev(*fullDefField) && (*fullDefField)));
87 sqrtk = new volScalarField((-(*bbb) + sqrt(sqr(*bbb) + 4*(*aaa)*(*ccc)))*(*inv2aaa));
88 nut = new volScalarField(Ck*(*delta)*(*sqrtk));
89}
90
91
92void tutorial27_online::evaluateApproxNut(const Eigen::VectorXd& reducedCoeffs)
93{
94 *fullDefField = defTensorOfModesAtMg[0];
95 for (int c = 0 ; c < reducedCoeffs.size() ; c++)
96 {
97 *fullDefField += reducedCoeffs(c)*defTensorOfModesAtMg[c+1];
98 }
99 *bbb = (2.0/3.0) * tr(*fullDefField);
100 *ccc = 2*Ck * (*delta) * ((dev(*fullDefField) && (*fullDefField)));
101 *sqrtk = mag(-(*bbb) + sqrt(sqr(*bbb) + 4*(*aaa) * (*ccc))) * (*inv2aaa);
102 *nut = Ck * (*delta) * (*sqrtk);
103 for (int i = 0; i < nut0->size(); i++)
104 {
105 (*nut0)[i] = (*nut)[i];
106 }
107 nut0->correctBoundaryConditions();
108}
109
110Eigen::VectorXd tutorial27_online::computeApproxSmagMg(const Eigen::VectorXd& reducedCoeffs)
111{
112 evaluateApproxNut(reducedCoeffs);
113 volVectorField stressField = fvc::div(2*(*nut0) * dev(*fullDefField)) - *meanSmagOnMagicNeighborhoods;
114
115 Eigen::VectorXd output = Eigen::VectorXd::Zero(d * (nMagicPoints + 1));
116 for (int i = 0; i < nMagicPoints; i++)
117 {
118 vector stressVector = weightAtMg(i) * (stressField)[localMagicPoints[i]];
119
120 output(i * d) = stressVector.x();
121 output(i * d + 1) = stressVector.y();
122 output(i * d + 2) = stressVector.z();
123 }
124 output(d * nMagicPoints) = 1.0;
125 return output;
126}
127
128Eigen::VectorXd tutorial27_online::computeApproxNutMg(const Eigen::VectorXd& reducedCoeffs)
129{
130 evaluateApproxNut(reducedCoeffs);
131 *nut0 -= *meanNutOnMagicPoints;
132
133 Eigen::VectorXd output(nMagicPoints + 1);
134 for (int i = 0; i < nMagicPoints; i++)
135 {
136 output(i) = weightAtMg(i) * (*nut0)[localMagicPoints[i]];
137 }
138 output(nMagicPoints) = 1.0;
139 return output;
140}
141
142Eigen::VectorXd tutorial27_online::predictSmagROMCoeffs(const Eigen::VectorXd& reducedCoeffs)
143{
144 if (ITHACAutilities::containsSubstring(interpolatedField, "fullStressFunction"))
145 {
146 Eigen::MatrixXd projected_K_DEIM = m_parameters->get_projected_K_DEIM();
147 Eigen::VectorXd smagVect(computeApproxSmagMg(reducedCoeffs));
148
149 return massMatrixInv*projected_K_DEIM*smagVect;
150 }
151
152 else if (ITHACAutilities::containsSubstring(interpolatedField, "nut"))
153 {
154 Eigen::VectorXd nutVect(computeApproxNutMg(reducedCoeffs));
155 Eigen::Tensor<double, 3 > xi_complete_onMagicPts(m_parameters->get_xi_onMagicPts());
156 Eigen::VectorXd b_extended(reducedCoeffs.size() + 1);
157 b_extended << 1.0,reducedCoeffs;
158
159 Eigen::VectorXd output(nModesU);
160 for (int i = 0; i < nModesU; i++)
161 {
162 output(i) = 0;
163 for (int j = 0 ; j < nMagicPoints +1; j++)
164 {
165 for (int q = 0 ; q < nModesU + 1 ; q++)
166 {
167 output(i) += xi_complete_onMagicPts(q,j,i) * b_extended(q) * nutVect(j);
168 }
169 }
170 }
171 return massMatrixInv*output;
172 }
173}
174
175// Compute a vector field onto velocity modes from its reduced temporal modes. Homogenize to a stress if specified.
176volVectorField tutorial27_online::computeROMproj_fromCoeffs(const Eigen::VectorXd& reducedCoeffs, bool stressUnit)
177{
178 Eigen::MatrixXd reducedCoeffsMatrix(nModesU, 1);
179 for (label k = 0; k < nModesU; k++)
180 {
181 reducedCoeffsMatrix(k,0) = reducedCoeffs[k];
182 }
183 PtrList<volVectorField> reconstruction = ITHACAutilities::reconstructFromCoeff(spatialModesU, reducedCoeffsMatrix, nModesU);
184
185 if (stressUnit)
186 {
187 // Dummy scalar to homogenized the reconstruction
188 dimensionedScalar time_inv("time_inv", dimensionSet(0,0,-1,0,0), scalar(1.0));
189 return reconstruction[0]*time_inv;
190 }
191 else
192 {
193 return reconstruction[0];
194 }
195}
196
197// Compute the coefficients of a vector field in the velocity basis (V^T f)
198Eigen::VectorXd tutorial27_online::computeROMcoeffs_fromFullDim(volVectorField& f_full)
199{
200 bool consider_volumes = true;
201 Eigen::MatrixXd coeffsVelocityPOD = ITHACAutilities::getCoeffs(f_full, spatialModesU, nModesU, consider_volumes);
202
203 return coeffsVelocityPOD.col(0);
204}
205
206// Compute f
207volVectorField tutorial27_online::computeSmagTerm_fromChronos(const Eigen::VectorXd& reducedCoeffs)
208{
209 return m_UnsteadyNSTurb->computeSmagTerm_fromU(*meanU + computeROMproj_fromCoeffs(reducedCoeffs));
210}
211
212
213void tutorial27_online::prediction()
214{
215 word folder_results = "./ITHACAoutput/Online/" + m_parameters->get_HRMethod() + "_" + interpolatedField.substr(7)
216 + "U_" + std::to_string(nMagicPoints) + "MgPts/";
217 mkDir(folder_results);
218 Eigen::MatrixXd predictedCoeffs(m_parameters->get_nSnapshotsSimulation(), nModesU);
219 Eigen::MatrixXd exactCoeffs(m_parameters->get_nSnapshotsSimulation(), nModesU);
220 Eigen::VectorXd relProjError(m_parameters->get_nSnapshotsSimulation());
221
222 for (label t = 0; t < m_parameters->get_nSnapshotsSimulation(); t++)
223 {
224 label index_time = t + m_parameters->get_startTime() + m_parameters->get_nSnapshots() - 1;
225
226 // Computing prediction
227 predictedCoeffs.row(t) = predictSmagROMCoeffs(temporalModesUSimulation.row(t));
228 volVectorField predictedSmagProj = computeROMproj_fromCoeffs(predictedCoeffs.row(t), true);
229
230 // Computing references from reduced velocity
231 volVectorField exactSmag = computeSmagTerm_fromChronos(temporalModesUSimulation.row(t));
232 exactCoeffs.row(t) = computeROMcoeffs_fromFullDim(exactSmag);
233 volVectorField exactSmagProj = computeROMproj_fromCoeffs(exactCoeffs.row(t), true);
234
235 // Evaluating errors with reference
236 relProjError(t) = ITHACAutilities::errorL2Rel(exactSmagProj, predictedSmagProj);
237
238 std::string idxTimeStr(runTime2.times()[index_time].name());
239 ITHACAstream::exportSolution(exactSmagProj, idxTimeStr, folder_results + "/exactSmagProj","fullStressFunction");
240 ITHACAstream::exportSolution(predictedSmagProj, idxTimeStr, folder_results + "/predictedSmagProj","fullStressFunction");
241 }
242 cnpy::save(predictedCoeffs, folder_results + "predictedCoeffs.npy");
243 cnpy::save(exactCoeffs, folder_results + "exactCoeffs.npy");
244 cnpy::save(relProjError, folder_results + "relativeSmagProjError.npy");
245}
246
Class that contains all parameters of the stochastic POD.
Implementation of a parametrized full order unsteady NS problem and preparation of the reduced matr...
void exportSolution(GeometricField< Type, PatchField, GeoMesh > &s, fileName subfolder, fileName folder, word fieldName)
Export a field to file in a certain folder and subfolder.
void read_fields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &Lfield, word Name, fileName casename, int first_snap, int n_snap)
Function to read a list of fields from the name of the field and casename.
Eigen::VectorXd getCoeffs(GeometricField< Type, PatchField, GeoMesh > &snapshot, PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, label Nmodes, bool consider_volumes)
Projects a snapshot on a basis function and gets the coefficients of the projection.
PtrList< GeometricField< Type, PatchField, GeoMesh > > reconstructFromCoeff(PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, Eigen::MatrixXd &coeff_matrix, label Nmodes)
Exact reconstruction using a certain number of modes for a list of fields and the projection coeffici...
bool containsSubstring(std::string contain, std::string contained)
Returns true if contained is a substring of contain, false otherwise.
double errorL2Rel(GeometricField< T, fvPatchField, volMesh > &field1, GeometricField< T, fvPatchField, volMesh > &field2, List< label > *labels)
Computes the relative error between two geometric Fields in L2 norm.
Eigen::MatrixXd getMassMatrix(PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, label Nmodes, bool consider_volumes)
Gets the mass matrix using the eigen routine.