Loading...
Searching...
No Matches
reductionProblem.C
Go to the documentation of this file.
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-------------------------------------------------------------------------------
12
13License
14 This file is part of ITHACA-FV
15
16 ITHACA-FV is free software: you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 ITHACA-FV is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with ITHACA-FV. If not, see <http://www.gnu.org/licenses/>.
28
29\*---------------------------------------------------------------------------*/
30
31
34
35
36#include "reductionProblem.H"
37
38// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
39
40// Constructor
44
45
46// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
47
48// Set the parameters
50{
51 mu.resize(Pnumber, Tnumber);
52 mu_range.resize(Pnumber, 2);
53}
54
55// Generate Random Parameters
57{
58 for (label k = 0; k < Pnumber; k++)
59 {
60 for (label n = 0; n < Tnumber; ++n)
61 {
62 mu(k, n) = mu_range(k, 0) + static_cast <float> (rand()) / static_cast <float>
63 (RAND_MAX / (mu_range(k, 1) - mu_range(k, 0))); // generate numbers
64 }
65 }
66}
67
69{
70 mu.resize(Tsize, Pnumber);
71 std::srand(std::time(0));
72 auto rand = Eigen::MatrixXd::Random(Tsize, Pnumber);
73 auto dx = mu_range.col(1) - mu_range.col(0);
74 Eigen::MatrixXd k;
75 k = (rand.array() + double(1)) / 2;
76
77 for (label i = 0; i < Pnumber; i ++)
78 {
79 k.col(i) = (k.col(i) * dx(i)).array() + mu_range(i, 0);
80 }
81
82 mu = k;
83}
84
85// Generate Equidistributed Parameters
87{
88 Eigen::VectorXd vec;
89
90 for (label k = 0; k < Pnumber; k++)
91 {
92 mu.row(k) = vec.LinSpaced(Tnumber, mu_range(k, 0), mu_range(k, 1));
93 }
94}
95
96// Perform a TruthSolve (To be overridden)
98{
99 Info << "reductionProblem::truthSolve() is a Method to be overridden -> Exiting the code"
100 << endl;
101 exit(0);
102}
103
104// Assign a BC for a vector field
105void reductionProblem::assignBC(volScalarField& s, label BC_ind, double& value)
106{
107 if (s.boundaryField()[BC_ind].type() == "fixedValue"
108 || s.boundaryField()[BC_ind].type() == "processor")
109 {
110 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
111 {
112 s.boundaryFieldRef()[BC_ind][i] = value;
113 }
114 }
115 else if (s.boundaryField()[BC_ind].type() == "fixedGradient")
116 {
117 fixedGradientFvPatchScalarField& Tpatch =
118 refCast<fixedGradientFvPatchScalarField>(s.boundaryFieldRef()[BC_ind]);
119 scalarField& gradTpatch = Tpatch.gradient();
120 forAll(gradTpatch, faceI)
121 {
122 gradTpatch[faceI] = value;
123 }
124 }
125 else if (s.boundaryField()[BC_ind].type() == "fixedFluxPressure")
126 {
127 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
128 {
129 s.boundaryFieldRef()[BC_ind][i] = value;
130 }
131 }
132 else if (s.boundaryField()[BC_ind].type() == "freestream")
133 {
134 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
135 {
136 s.boundaryFieldRef()[BC_ind][i] = value;
137 }
138
139 freestreamFvPatchField<scalar>& Tpatch =
140 refCast<freestreamFvPatchField<scalar>>(s.boundaryFieldRef()[BC_ind]);
141 scalarField& gradTpatch = Tpatch.freestreamValue();
142 forAll(gradTpatch, faceI)
143 {
144 gradTpatch[faceI] = value;
145 }
146 }
147 else if (s.boundaryField()[BC_ind].type() == "calculated")
148 {
149 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
150 {
151 s.boundaryFieldRef()[BC_ind][i] = value;
152 }
153 }
154 else if (s.boundaryField()[BC_ind].type() == "empty")
155 {
156 }
157}
158
159// Assign a BC for a scalar field
160void reductionProblem::assignBC(volVectorField& s, label BC_ind,
161 Vector<double>& value)
162{
163 if (s.boundaryField()[BC_ind].type() == "fixedValue")
164 {
165 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
166 {
167 s.boundaryFieldRef()[BC_ind][i] = value;
168 }
169 }
170 else if (s.boundaryField()[BC_ind].type() == "fixedGradient")
171 {
172 Info << "This Feature is not implemented for this boundary condition" << endl;
173 exit(0);
174 }
175 else if (s.boundaryField()[BC_ind].type() == "freestream")
176 {
177 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
178 {
179 s.boundaryFieldRef()[BC_ind][i] = value;
180 }
181
182 freestreamFvPatchField<vector>& Tpatch =
183 refCast<freestreamFvPatchField<vector>>(s.boundaryFieldRef()[BC_ind]);
184 vectorField& gradTpatch = Tpatch.freestreamValue();
185 forAll(gradTpatch, faceI)
186 {
187 gradTpatch[faceI] = value;
188 }
189 }
190}
191
192// Reconstruct using a Matrix of coefficients (vector field)
193void reductionProblem::reconstructFromMatrix(PtrList<volVectorField>&
194 rec_field2, PtrList<volVectorField>& modes, label Nmodes,
195 Eigen::MatrixXd coeff_matrix)
196{
197 for (label k = 0; k < coeff_matrix.cols(); k++)
198 {
199 for (label i = 0; i < Nmodes; i++)
200 {
201 if ( i == 0)
202 {
203 rec_field2.append(coeff_matrix(i, k)*modes[i]);
204 }
205 else
206 {
207 rec_field2[k] += coeff_matrix(i, k) * modes[i];
208 }
209 }
210 }
211}
212
213
214// Reconstruct using a Matrix of coefficients (vector field)
215void reductionProblem::reconstructFromMatrix(PtrList<volScalarField>&
216 rec_field2, PtrList<volScalarField>& modes, label Nmodes,
217 Eigen::MatrixXd coeff_matrix)
218{
219 for (label k = 0; k < coeff_matrix.cols(); k++)
220 {
221 for (label i = 0; i < Nmodes; i++)
222 {
223 if ( i == 0)
224 {
225 rec_field2.append(coeff_matrix(i, k)*modes[i]);
226 }
227 else
228 {
229 rec_field2[k] += coeff_matrix(i, k) * modes[i];
230 }
231 }
232 }
233}
234
236{
237 Info << "reductionProblem::project is a function to be overridden exiting the code"
238 << endl;
239 exit(0);
240}
241
242void reductionProblem::writeMu(List<scalar> mu_now)
243{
244 mkDir("./ITHACAoutput/Parameters");
245 std::ofstream ofs;
246 ofs.open ("./ITHACAoutput/Parameters/par",
247 std::ofstream::out | std::ofstream::app);
248 forAll(mu_now, i)
249 {
250 ofs << mu_now[i] << ' ';
251 }
252 ofs << "\n";
253 ofs.close();
254}
255
257{
258 Info << "reductionProblem::liftSolve is a virtual function it must be overridden"
259 << endl;
260 exit(0);
261}
262
264{
265 Info << "reductionProblem::liftSolveT is a virtual function it must be overridden"
266 << endl;
267 exit(0);
268}
269
270std::vector<SPLINTER::RBFSpline> reductionProblem::getCoeffManifoldRBF(
271 PtrList<volVectorField> snapshots, PtrList<volVectorField>& modes,
272 word rbfBasis)
273{
274 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
275 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
276 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
277 std::vector<SPLINTER::RBFSpline> rbfsplines;
278 rbfsplines.reserve(coeff.rows());
279 // Check that each column of matrix "mu_samples" does not satisfy the case where all elements hold same value (which might appear for e.g. unsteady non-parametric problems)
280 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
281 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
282
283 for (label i = 0; i < mu_samples.cols(); i++)
284 {
285 double firstVal = mu_samples(0, i);
286 bool isConst = (mu_samples.col(i).array() == firstVal).all();
287
288 // Consider only columns with non-constant values
289 if (isConst == 0)
290 {
291 muSampRefined.conservativeResize(muSampRefined.rows(),
292 muSampRefined.cols() + 1);
293 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
294 }
295 }
296
297 // --- Loop over Nmodes
298 for (label i = 0; i < coeff.rows(); i++)
299 {
300 SPLINTER::DataTable samples;
301
302 // --- Loop over Nsamples
303 for (label j = 0; j < mu_samples.rows(); j++)
304 {
305 SPLINTER::DenseVector x(muSampRefined.cols());
306
307 // --- Loop over Nparameters
308 for (label k = 0; k < muSampRefined.cols(); k++)
309 {
310 x(k) = muSampRefined(j, k);
311 }
312
313 samples.addSample(x, coeff(i, j));
314 }
315
316 if (rbfBasis == "GAUSSIAN")
317 {
318 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
319 SPLINTER::RadialBasisFunctionType::GAUSSIAN));
320 }
321 else if (rbfBasis == "THIN_PLATE")
322 {
323 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
324 SPLINTER::RadialBasisFunctionType::THIN_PLATE_SPLINE));
325 }
326 else if (rbfBasis == "MULTI_QUADRIC")
327 {
328 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
329 SPLINTER::RadialBasisFunctionType::MULTIQUADRIC));
330 }
331 else if (rbfBasis == "INVERSE_QUADRIC")
332 {
333 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
334 SPLINTER::RadialBasisFunctionType::INVERSE_QUADRIC));
335 }
336 else if (rbfBasis == "INVERSE_MULTI_QUADRIC")
337 {
338 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
339 SPLINTER::RadialBasisFunctionType::INVERSE_MULTIQUADRIC));
340 }
341 else
342 {
343 std::cout <<
344 "Unknown string for rbfBasis. Valid types are 'GAUSSIAN', 'THIN_PLATE', 'MULTI_QUADRIC', 'INVERSE_QUADRIC', 'INVERSE_MULTI_QUADRIC'"
345 << std::endl;
346 exit(0);
347 }
348 }
349
350 return rbfsplines;
351}
352
353
354std::vector<SPLINTER::RBFSpline> reductionProblem::getCoeffManifoldRBF(
355 PtrList<volScalarField> snapshots, PtrList<volScalarField>& modes,
356 word rbfBasis)
357{
358 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
359 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
360 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
361 std::vector<SPLINTER::RBFSpline> rbfsplines;
362 rbfsplines.reserve(coeff.rows());
363 // Check that each column of matrix "mu_samples" does not satisfy the case where all elements hold same value (which might appear for e.g. unsteady non-parametric problems)
364 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
365 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
366
367 for (label i = 0; i < mu_samples.cols(); i++)
368 {
369 double firstVal = mu_samples(0, i);
370 bool isConst = (mu_samples.col(i).array() == firstVal).all();
371
372 // Consider only columns with non-constant values
373 if (isConst == 0)
374 {
375 muSampRefined.conservativeResize(muSampRefined.rows(),
376 muSampRefined.cols() + 1);
377 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
378 }
379 }
380
381 // --- Loop over Nmodes
382 for (label i = 0; i < coeff.rows(); i++)
383 {
384 SPLINTER::DataTable samples;
385
386 // --- Loop over Nsamples
387 for (label j = 0; j < mu_samples.rows(); j++)
388 {
389 SPLINTER::DenseVector x(muSampRefined.cols());
390
391 // --- Loop over Nparameters
392 for (label k = 0; k < muSampRefined.cols(); k++)
393 {
394 x(k) = muSampRefined(j, k);
395 }
396
397 samples.addSample(x, coeff(i, j));
398 }
399
400 if (rbfBasis == "GAUSSIAN")
401 {
402 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
403 SPLINTER::RadialBasisFunctionType::GAUSSIAN));
404 }
405 else if (rbfBasis == "THIN_PLATE")
406 {
407 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
408 SPLINTER::RadialBasisFunctionType::THIN_PLATE_SPLINE));
409 }
410 else if (rbfBasis == "MULTI_QUADRIC")
411 {
412 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
413 SPLINTER::RadialBasisFunctionType::MULTIQUADRIC));
414 }
415 else if (rbfBasis == "INVERSE_QUADRIC")
416 {
417 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
418 SPLINTER::RadialBasisFunctionType::INVERSE_QUADRIC));
419 }
420 else if (rbfBasis == "INVERSE_MULTI_QUADRIC")
421 {
422 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
423 SPLINTER::RadialBasisFunctionType::INVERSE_MULTIQUADRIC));
424 }
425 else
426 {
427 std::cout <<
428 "Unknown string for rbfBasis. Valid types are 'GAUSSIAN', 'THIN_PLATE', 'MULTI_QUADRIC', 'INVERSE_QUADRIC', 'INVERSE_MULTI_QUADRIC'"
429 << std::endl;
430 exit(0);
431 }
432 }
433
434 return rbfsplines;
435}
436
437
438std::vector<SPLINTER::BSpline> reductionProblem::getCoeffManifoldSPL(
439 PtrList<volVectorField> snapshots, PtrList<volVectorField>& modes, label splDeg)
440{
441 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
442 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
443 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
444 std::vector<SPLINTER::BSpline> bsplines;
445 bsplines.reserve(coeff.rows());
446 // Check that each column of matrix "mu_samples" does not satisfy the case where all elements hold same value (which might appear for e.g. unsteady non-parametric problems)
447 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
448 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
449
450 for (label i = 0; i < mu_samples.cols(); i++)
451 {
452 double firstVal = mu_samples(0, i);
453 bool isConst = (mu_samples.col(i).array() == firstVal).all();
454
455 // Consider only columns with non-constant values
456 if (isConst == 0)
457 {
458 muSampRefined.conservativeResize(muSampRefined.rows(),
459 muSampRefined.cols() + 1);
460 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
461 }
462 }
463
464 // --- Loop over Nmodes
465 for (label i = 0; i < coeff.rows(); i++)
466 {
467 SPLINTER::DataTable samples;
468
469 // --- Loop over Nsamples
470 for (label j = 0; j < mu_samples.rows(); j++)
471 {
472 SPLINTER::DenseVector x(muSampRefined.cols());
473
474 // --- Loop over Nparameters
475 for (label k = 0; k < muSampRefined.cols(); k++)
476 {
477 x(k) = muSampRefined(j, k);
478 }
479
480 samples.addSample(x, coeff(i, j));
481 }
482
483 SPLINTER::BSpline bspline = SPLINTER::BSpline::Builder(samples).degree(
484 splDeg).build();
485 bsplines.push_back(bspline);
486 }
487
488 return bsplines;
489}
490
491
492std::vector<SPLINTER::BSpline> reductionProblem::getCoeffManifoldSPL(
493 PtrList<volScalarField> snapshots, PtrList<volScalarField>& modes, label splDeg)
494{
495 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
496 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
497 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
498 std::vector<SPLINTER::BSpline> bsplines;
499 bsplines.reserve(coeff.rows());
500 // Check that each column of matrix "mu_samples" does not satisfy the case where all elements hold same value (which might appear for e.g. unsteady non-parametric problems)
501 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
502 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
503
504 for (label i = 0; i < mu_samples.cols(); i++)
505 {
506 double firstVal = mu_samples(0, i);
507 bool isConst = (mu_samples.col(i).array() == firstVal).all();
508
509 // Consider only columns with non-constant values
510 if (isConst == 0)
511 {
512 muSampRefined.conservativeResize(muSampRefined.rows(),
513 muSampRefined.cols() + 1);
514 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
515 }
516 }
517
518 // --- Loop over Nmodes
519 for (label i = 0; i < coeff.rows(); i++)
520 {
521 SPLINTER::DataTable samples;
522
523 // --- Loop over Nsamples
524 for (label j = 0; j < mu_samples.rows(); j++)
525 {
526 SPLINTER::DenseVector x(muSampRefined.cols());
527
528 // --- Loop over Nparameters
529 for (label k = 0; k < muSampRefined.cols(); k++)
530 {
531 x(k) = muSampRefined(j, k);
532 }
533
534 samples.addSample(x, coeff(i, j));
535 }
536
537 SPLINTER::BSpline bspline = SPLINTER::BSpline::Builder(samples).degree(
538 splDeg).build();
539 bsplines.push_back(bspline);
540 }
541
542 return bsplines;
543}
544
545// ************************************************************************* //
546
forAll(example_CG.gList, solutionI)
Definition CGtest.H:21
#define M_Assert(Expr, Msg)
void project()
General projection operation.
void writeMu(List< scalar > mu_now)
Write out a list of scalar corresponding to the parameters used in the truthSolve.
label Pnumber
Number of parameters.
void reconstructFromMatrix(PtrList< volVectorField > &rec_field2, PtrList< volVectorField > &modes, label Nmodes, Eigen::MatrixXd coeff_matrix)
Exact reconstruction using a certain number of modes for vector list of fields and the projection coe...
Eigen::MatrixXd mu_samples
Matrix of parameters to be used for PODI, where each row corresponds to a sample point....
reductionProblem()
Construct Null.
void assignBC(volVectorField &s, label BC_ind, Vector< double > &value)
Assign Boundary Condition to a volVectorField.
label Tnumber
Dimension of the training set (used only when gerating parameters without input)
void genRandPar()
Generate Random Numbers.
Eigen::MatrixXd mu
Row matrix of parameters.
Eigen::MatrixXd mu_range
Range of the parameter spaces.
void setParameters()
Set Parameters Problems.
void liftSolve()
Virtual function to compute the lifting function for scalar field.
void truthSolve()
Perform a TruthSolve.
std::vector< SPLINTER::BSpline > getCoeffManifoldSPL(PtrList< volVectorField > snapshots, PtrList< volVectorField > &modes, label splDeg=3)
Constructs the parameters-coefficients manifold for vector fields, based on the B-spline model.
std::vector< SPLINTER::RBFSpline > getCoeffManifoldRBF(PtrList< volVectorField > snapshots, PtrList< volVectorField > &modes, word rbfBasis="GAUSSIAN")
Constructs the parameters-coefficients manifold for vector fields, based on RBF-spline model.
void genEquiPar()
Generate Equidistributed Numbers.
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.
Header file of the reductionProblem class.
label i
Definition pEqn.H:46