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
148 else if (s.boundaryField()[BC_ind].type() == "calculated")
149 {
150 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
151 {
152 s.boundaryFieldRef()[BC_ind][i] = value;
153 }
154 }
155
156 else if (s.boundaryField()[BC_ind].type() == "empty")
157 {
158 }
159}
160
161// Assign a BC for a scalar field
162void reductionProblem::assignBC(volVectorField& s, label BC_ind,
163 Vector<double>& value)
164{
165 if (s.boundaryField()[BC_ind].type() == "fixedValue")
166 {
167 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
168 {
169 s.boundaryFieldRef()[BC_ind][i] = value;
170 }
171 }
172 else if (s.boundaryField()[BC_ind].type() == "fixedGradient")
173 {
174 Info << "This Feature is not implemented for this boundary condition" << endl;
175 exit(0);
176 }
177 else if (s.boundaryField()[BC_ind].type() == "freestream")
178 {
179 for (label i = 0; i < s.boundaryField()[BC_ind].size(); i++)
180 {
181 s.boundaryFieldRef()[BC_ind][i] = value;
182 }
183
184 freestreamFvPatchField<vector>& Tpatch =
185 refCast<freestreamFvPatchField<vector >> (s.boundaryFieldRef()[BC_ind]);
186 vectorField& gradTpatch = Tpatch.freestreamValue();
187 forAll(gradTpatch, faceI)
188 {
189 gradTpatch[faceI] = value;
190 }
191 }
192}
193
194// Reconstruct using a Matrix of coefficients (vector field)
195void reductionProblem::reconstructFromMatrix(PtrList<volVectorField>&
196 rec_field2, PtrList<volVectorField>& modes, label Nmodes,
197 Eigen::MatrixXd coeff_matrix)
198{
199 for (label k = 0; k < coeff_matrix.cols(); k++)
200 {
201 for (label i = 0; i < Nmodes; i++)
202 {
203 if ( i == 0)
204 {
205 rec_field2.append(coeff_matrix(i, k) * modes[i]);
206 }
207 else
208 {
209 rec_field2[k] += coeff_matrix(i, k) * modes[i];
210 }
211 }
212 }
213}
214
215
216// Reconstruct using a Matrix of coefficients (vector field)
217void reductionProblem::reconstructFromMatrix(PtrList<volScalarField>&
218 rec_field2, PtrList<volScalarField>& modes, label Nmodes,
219 Eigen::MatrixXd coeff_matrix)
220{
221 for (label k = 0; k < coeff_matrix.cols(); k++)
222 {
223 for (label i = 0; i < Nmodes; i++)
224 {
225 if ( i == 0)
226 {
227 rec_field2.append(coeff_matrix(i, k) * modes[i]);
228 }
229 else
230 {
231 rec_field2[k] += coeff_matrix(i, k) * modes[i];
232 }
233 }
234 }
235}
236
238{
239 Info << "reductionProblem::project is a function to be overridden exiting the code"
240 << endl;
241 exit(0);
242}
243
244void reductionProblem::writeMu(List<scalar> mu_now)
245{
246 mkDir("./ITHACAoutput/Parameters");
247 std::ofstream ofs;
248 ofs.open ("./ITHACAoutput/Parameters/par",
249 std::ofstream::out | std::ofstream::app);
250 forAll(mu_now, i)
251 {
252 ofs << mu_now[i] << ' ';
253 }
254
255 ofs << "\n";
256 ofs.close();
257}
258
260{
261 Info << "reductionProblem::liftSolve is a virtual function it must be overridden"
262 << endl;
263 exit(0);
264}
265
267{
268 Info << "reductionProblem::liftSolveT is a virtual function it must be overridden"
269 << endl;
270 exit(0);
271}
272
273std::vector<SPLINTER::RBFSpline> reductionProblem::getCoeffManifoldRBF(
274 PtrList<volVectorField> snapshots, PtrList<volVectorField>& modes,
275 word rbfBasis)
276{
277 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
278 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
279 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
280 std::vector<SPLINTER::RBFSpline> rbfsplines;
281 rbfsplines.reserve(coeff.rows());
282 // 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)
283 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
284 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
285
286 for (label i = 0; i < mu_samples.cols(); i++)
287 {
288 double firstVal = mu_samples(0, i);
289 bool isConst = (mu_samples.col(i).array() == firstVal).all();
290
291 // Consider only columns with non-constant values
292 if (isConst == 0)
293 {
294 muSampRefined.conservativeResize(muSampRefined.rows(),
295 muSampRefined.cols() + 1);
296 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
297 }
298 }
299
300 // --- Loop over Nmodes
301 for (label i = 0; i < coeff.rows(); i++)
302 {
303 SPLINTER::DataTable samples;
304
305 // --- Loop over Nsamples
306 for (label j = 0; j < mu_samples.rows(); j++)
307 {
308 SPLINTER::DenseVector x(muSampRefined.cols());
309
310 // --- Loop over Nparameters
311 for (label k = 0; k < muSampRefined.cols(); k++)
312 {
313 x(k) = muSampRefined(j, k);
314 }
315
316 samples.addSample(x, coeff(i, j));
317 }
318
319 if (rbfBasis == "GAUSSIAN")
320 {
321 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
322 SPLINTER::RadialBasisFunctionType::GAUSSIAN));
323 }
324 else if (rbfBasis == "THIN_PLATE")
325 {
326 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
327 SPLINTER::RadialBasisFunctionType::THIN_PLATE_SPLINE));
328 }
329 else if (rbfBasis == "MULTI_QUADRIC")
330 {
331 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
332 SPLINTER::RadialBasisFunctionType::MULTIQUADRIC));
333 }
334 else if (rbfBasis == "INVERSE_QUADRIC")
335 {
336 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
337 SPLINTER::RadialBasisFunctionType::INVERSE_QUADRIC));
338 }
339 else if (rbfBasis == "INVERSE_MULTI_QUADRIC")
340 {
341 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
342 SPLINTER::RadialBasisFunctionType::INVERSE_MULTIQUADRIC));
343 }
344 else
345 {
346 std::cout <<
347 "Unknown string for rbfBasis. Valid types are 'GAUSSIAN', 'THIN_PLATE', 'MULTI_QUADRIC', 'INVERSE_QUADRIC', 'INVERSE_MULTI_QUADRIC'"
348 << std::endl;
349 exit(0);
350 }
351 }
352
353 return rbfsplines;
354}
355
356
357std::vector<SPLINTER::RBFSpline> reductionProblem::getCoeffManifoldRBF(
358 PtrList<volScalarField> snapshots, PtrList<volScalarField>& modes,
359 word rbfBasis)
360{
361 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
362 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
363 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
364 std::vector<SPLINTER::RBFSpline> rbfsplines;
365 rbfsplines.reserve(coeff.rows());
366 // 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)
367 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
368 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
369
370 for (label i = 0; i < mu_samples.cols(); i++)
371 {
372 double firstVal = mu_samples(0, i);
373 bool isConst = (mu_samples.col(i).array() == firstVal).all();
374
375 // Consider only columns with non-constant values
376 if (isConst == 0)
377 {
378 muSampRefined.conservativeResize(muSampRefined.rows(),
379 muSampRefined.cols() + 1);
380 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
381 }
382 }
383
384 // --- Loop over Nmodes
385 for (label i = 0; i < coeff.rows(); i++)
386 {
387 SPLINTER::DataTable samples;
388
389 // --- Loop over Nsamples
390 for (label j = 0; j < mu_samples.rows(); j++)
391 {
392 SPLINTER::DenseVector x(muSampRefined.cols());
393
394 // --- Loop over Nparameters
395 for (label k = 0; k < muSampRefined.cols(); k++)
396 {
397 x(k) = muSampRefined(j, k);
398 }
399
400 samples.addSample(x, coeff(i, j));
401 }
402
403 if (rbfBasis == "GAUSSIAN")
404 {
405 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
406 SPLINTER::RadialBasisFunctionType::GAUSSIAN));
407 }
408 else if (rbfBasis == "THIN_PLATE")
409 {
410 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
411 SPLINTER::RadialBasisFunctionType::THIN_PLATE_SPLINE));
412 }
413 else if (rbfBasis == "MULTI_QUADRIC")
414 {
415 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
416 SPLINTER::RadialBasisFunctionType::MULTIQUADRIC));
417 }
418 else if (rbfBasis == "INVERSE_QUADRIC")
419 {
420 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
421 SPLINTER::RadialBasisFunctionType::INVERSE_QUADRIC));
422 }
423 else if (rbfBasis == "INVERSE_MULTI_QUADRIC")
424 {
425 rbfsplines.push_back(SPLINTER::RBFSpline(samples,
426 SPLINTER::RadialBasisFunctionType::INVERSE_MULTIQUADRIC));
427 }
428 else
429 {
430 std::cout <<
431 "Unknown string for rbfBasis. Valid types are 'GAUSSIAN', 'THIN_PLATE', 'MULTI_QUADRIC', 'INVERSE_QUADRIC', 'INVERSE_MULTI_QUADRIC'"
432 << std::endl;
433 exit(0);
434 }
435 }
436
437 return rbfsplines;
438}
439
440
441std::vector<SPLINTER::BSpline> reductionProblem::getCoeffManifoldSPL(
442 PtrList<volVectorField> snapshots, PtrList<volVectorField>& modes,
443 label splDeg)
444{
445 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
446 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
447 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
448 std::vector<SPLINTER::BSpline> bsplines;
449 bsplines.reserve(coeff.rows());
450 // 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)
451 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
452 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
453
454 for (label i = 0; i < mu_samples.cols(); i++)
455 {
456 double firstVal = mu_samples(0, i);
457 bool isConst = (mu_samples.col(i).array() == firstVal).all();
458
459 // Consider only columns with non-constant values
460 if (isConst == 0)
461 {
462 muSampRefined.conservativeResize(muSampRefined.rows(),
463 muSampRefined.cols() + 1);
464 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
465 }
466 }
467
468 // --- Loop over Nmodes
469 for (label i = 0; i < coeff.rows(); i++)
470 {
471 SPLINTER::DataTable samples;
472
473 // --- Loop over Nsamples
474 for (label j = 0; j < mu_samples.rows(); j++)
475 {
476 SPLINTER::DenseVector x(muSampRefined.cols());
477
478 // --- Loop over Nparameters
479 for (label k = 0; k < muSampRefined.cols(); k++)
480 {
481 x(k) = muSampRefined(j, k);
482 }
483
484 samples.addSample(x, coeff(i, j));
485 }
486
487 SPLINTER::BSpline bspline = SPLINTER::BSpline::Builder(samples).degree(
488 splDeg).build();
489 bsplines.push_back(bspline);
490 }
491
492 return bsplines;
493}
494
495
496std::vector<SPLINTER::BSpline> reductionProblem::getCoeffManifoldSPL(
497 PtrList<volScalarField> snapshots, PtrList<volScalarField>& modes,
498 label splDeg)
499{
500 Eigen::MatrixXd coeff = ITHACAutilities::getCoeffs(snapshots, modes);
501 M_Assert(mu_samples.rows() == coeff.cols() * mu.rows(),
502 "The dimension of the coefficient matrix must correspond to the constructed parameter matrix 'mu_samples'");
503 std::vector<SPLINTER::BSpline> bsplines;
504 bsplines.reserve(coeff.rows());
505 // 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)
506 // In which case the spline builder uses a refined matrix "muSampRefined" that discards those columns aforementioned, hence allows for a feasible manifold construction
507 Eigen::MatrixXd muSampRefined(mu_samples.rows(), 0);
508
509 for (label i = 0; i < mu_samples.cols(); i++)
510 {
511 double firstVal = mu_samples(0, i);
512 bool isConst = (mu_samples.col(i).array() == firstVal).all();
513
514 // Consider only columns with non-constant values
515 if (isConst == 0)
516 {
517 muSampRefined.conservativeResize(muSampRefined.rows(),
518 muSampRefined.cols() + 1);
519 muSampRefined.col(muSampRefined.cols() - 1) = mu_samples.col(i);
520 }
521 }
522
523 // --- Loop over Nmodes
524 for (label i = 0; i < coeff.rows(); i++)
525 {
526 SPLINTER::DataTable samples;
527
528 // --- Loop over Nsamples
529 for (label j = 0; j < mu_samples.rows(); j++)
530 {
531 SPLINTER::DenseVector x(muSampRefined.cols());
532
533 // --- Loop over Nparameters
534 for (label k = 0; k < muSampRefined.cols(); k++)
535 {
536 x(k) = muSampRefined(j, k);
537 }
538
539 samples.addSample(x, coeff(i, j));
540 }
541
542 SPLINTER::BSpline bspline = SPLINTER::BSpline::Builder(samples).degree(
543 splDeg).build();
544 bsplines.push_back(bspline);
545 }
546
547 return bsplines;
548}
549
550// ************************************************************************* //
551
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