Loading...
Searching...
No Matches
sequentialIHTP.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
13 License
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
33
34
35#include "sequentialIHTP.H"
36
37// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
38
39// Constructors
40sequentialIHTP::sequentialIHTP() {}
41
42sequentialIHTP::sequentialIHTP(int argc, char* argv[])
43 :
44 DT("DT", dimensionSet(0, 2, -1, 0, 0, 0, 0), 1.0)
45{
46 _args = autoPtr<argList>
47 (
48 new argList(argc, argv)
49 );
50
51 if (!_args->checkRootCase())
52 {
53 Foam::FatalError.exit();
54 }
55
56 argList& args = _args();
57#include "createTime.H"
58#include "createMesh.H"
59 _simple = autoPtr<simpleControl>
60 (
61 new simpleControl
62 (
63 mesh
64 )
65 );
66#include "createFields.H"
67#include "createThermocouples.H"
68 thermocouplesPos = TCpos;
69#include "createFvOptions.H"
70 ITHACAdict = new IOdictionary
71 (
72 IOobject
73 (
74 "ITHACAdict",
75 runTime.system(),
76 mesh,
77 IOobject::MUST_READ,
78 IOobject::NO_WRITE
79 )
80 );
81#include "createRegularization.H"
82 para = ITHACAparameters::getInstance(mesh, runTime);
85 startTime = runTime.startTime().value();
86 deltaTime = runTime.deltaTValue();
87 endTime = runTime.endTime().value();
88 Ntimes = (endTime - startTime) / deltaTime;
89 timeSteps.resize( Ntimes + 1 );
90 forAll(timeSteps, timeI)
91 {
92 timeSteps[timeI] = startTime + (timeI) * deltaTime;
93 }
94 //Info << "debug: timeSteps = " << timeSteps << endl;
95 //Info << "debug: startTime = " << startTime << endl;
96 //Info << "debug: endTime = " << endTime << endl;
97 //Info << "debug: deltaTime = " << deltaTime << endl;
98}
99
100// * * * * * * * * * * * * * * Full Order Methods * * * * * * * * * * * * * * //
101
103{
104 diffusivity = _diff;
105}
106
107void sequentialIHTP::setSpaceBasis(word type, scalar shapeParameter, label Npod)
108{
109 if (!thermocouplesRead) // Kabir: It checks if the thermocouples have been read by evaluating the thermocouplesRead variable. If they haven't been read, it calls the readThermocouples function.
110 {
111 readThermocouples(); // Kabir:Defining positions of thermocouples
112 }
113
114 volScalarField& T = _T();
115 fvMesh& mesh = _mesh();
116 // ################### Kabir: Read coordinates of those selected thermocouples from ITHACAdict
117 Time& runTime = _runTime();
118 ITHACAparameters* para1 = new ITHACAparameters(mesh,
119 runTime); // Create an instance of ITHACAparameters with the required arguments
120 label NbasisInSpace =
121 para1->ITHACAdict->lookupOrDefault<label>("sizeOfTheParameter",
122 0); // label sizeOfParameter = 5;
123 // NbasisInSpace = 5; //thermocouplesNum; // RBF <= measurements
124 Eigen::VectorXd thermocoupleXValues(NbasisInSpace);
125 Eigen::VectorXd thermocoupleZValues(NbasisInSpace);
126 Eigen::VectorXd thermocoupleYValues(NbasisInSpace);
127 List<scalar> thermocoupleXList =
128 para1->ITHACAdict->subDict("thermocoupleCoordinates").lookup("XValues");
129 List<scalar> thermocoupleZList =
130 para1->ITHACAdict->subDict("thermocoupleCoordinates").lookup("ZValues");
131 List<scalar> thermocoupleYList =
132 para1->ITHACAdict->subDict("thermocoupleCoordinates").lookup("YValues");
133
134 //Kabir: Convert the lists to Eigen::VectorXd
135 for (label i = 0; i < NbasisInSpace; i++)
136 {
137 thermocoupleXValues(i) = thermocoupleXList[i];
138 thermocoupleZValues(i) = thermocoupleZList[i];
139 thermocoupleYValues(i) = thermocoupleYList[i];
140 }
141
142 // ################### Kabir: Read coordinates of those selected thermocouples from ITHACAdict
143 // Kabir: For defining the location of RBFs, we just project some of those selected measurement points on the boundary hotSide.
144 // Kabir: RBFs are center at thermocouple projection.
145 Info << "\nRadial Basis Functions are used." << endl;
146 Info << "The center of each function is at the projection " << endl;
147 Info << "of some selected thermocouple on the boundary hotSide." << endl;
148 Info << "RBFs must be less than measurements or at least are equal to measurements."
149 << endl;
150 Info << "If RBFs = measurements it means that we have one basis function in front of each thermocouples.\n\n";
151 // Kabir: Because RBFs are defined by a shape parameter and the center of the kernel(center of a radial basis function).
152 Eigen::MatrixXd radius_kb(NbasisInSpace,
153 T.boundaryField()[hotSide_ind].size()); // Kabir:
155 int thermocouplesCounter =
156 0; // I changed the code, we do not need this counter.
157 int rbfCenterTimeI =
158 0; // I changed the code, we do not need this counter.
159 // Kabir: It calculates the maximum X and Z coordinates of the face centers on the hot side boundary. No need to do that.
160 scalar maxX =
161 1.0; // Foam::max(mesh.boundaryMesh()[hotSide_ind].faceCentres().component(Foam::vector::X));
162 scalar maxZ =
163 1.0; // Foam::max(mesh.boundaryMesh()[hotSide_ind].faceCentres().component(Foam::vector::Z));
164 forAll(heatFluxSpaceBasis,
165 funcI) //5, Kabir: this loop will execute NbasisInSpace(5) times, once for each basis function.
166 {
167 // Kabir: Get the x and z coordinates of the thermocouple location
168 scalar thermocoupleX = thermocoupleXValues(funcI);
169 scalar thermocoupleZ = thermocoupleZValues(funcI);
170 scalar thermocoupleY = thermocoupleYValues(funcI);
171 // Kabir: Resize the heatFluxSpaceBasis[funcI] vector to match the size of hotSide boundary faces
172 heatFluxSpaceBasis[funcI].resize(T.boundaryField()[hotSide_ind].size());
173 forAll (T.boundaryField()[hotSide_ind], faceI)
174 {
175 scalar faceX =
176 mesh.boundaryMesh()[hotSide_ind].faceCentres()[faceI].x(); // Kabir: Get the x and z coordinates of the face center
177 scalar faceZ = mesh.boundaryMesh()[hotSide_ind].faceCentres()[faceI].z();
178 // Kabir: R is the distance value for the kernel. Calculate the distance (radius) between those selected thermocouples and face center
179 scalar radius = Foam::sqrt((faceX - thermocoupleX) * (faceX - thermocoupleX) /
180 maxX / maxX + (faceZ - thermocoupleZ) * (faceZ - thermocoupleZ) / maxZ / maxZ);
181 // Kabir: The normalization factors maxX and maxZ are used to ensure that the components (differences in x and z coordinates) are scaled properly be.fore calculating the radius.
182 // Kabir: I think the normalization factor should not be used and it must utilize just Euclidean distance itself. So we put maxX and maxZ equalt to
183 // Kabir: Store the calculated radius for later use
184 radius_kb(funcI, faceI) = radius;
185 // Kabir Calculate the value of the kernel function and assign it to heatFluxSpaceBasis[funcI][faceI]
186 heatFluxSpaceBasis[funcI][faceI] = Foam::sqrt(1 + (shapeParameter * radius) *
187 (shapeParameter * radius)); // Kabir: Multiquadric kernel
188 // heatFluxSpaceBasis[funcI][faceI] = Foam::exp(-1.0 * (shapeParameter * shapeParameter) * (radius * radius)); // Kabir: Gaussian kernel
189 // heatFluxSpaceBasis[funcI][faceI] = 1.0 / (1.0 + (shapeParameter * radius) * (shapeParameter * radius)); // Kabir: Inverse Quadratic Kernel
190 // heatFluxSpaceBasis[funcI][faceI] = 1.0 / Foam::sqrt(1.0 + (shapeParameter * radius) * (shapeParameter * radius)); // Kabir: Inverse Multiquadric Kernel
191 }
192 // Kabir: Increment the thermocouplesCounter to move to the next thermocouple location. I changed the code, we do not need this counter.
193 thermocouplesCounter++;
194 }
196 cnpy::save(radius_kb, "radius_kb.npy");
197 cnpy::save(thermocoupleXValues, "thermocoupleXValues.npy");
198 cnpy::save(thermocoupleZValues, "thermocoupleZValues.npy");
199 cnpy::save(thermocoupleYValues, "thermocoupleYValues.npy");
202 std::string heat_flux_space_basis = "heat_flux_space_basis";
203 std::string folderNamePrRb = "HeatFluxSpaceRBF";
204 std::string folderPathPrRb = "ITHACAoutput/projection/" + folderNamePrRb;
205 // Convert heatFluxSpaceBasis which is Foam::List<Foam::List<double>> object to heatFluxSpaceBasisMatrix which is Eigen::Matrix object before calling the exportMatrix function by using Eigen::Map constructor
206 Eigen::MatrixXd heatFluxSpaceBasisMatrix(heatFluxSpaceBasis.size(),
207 heatFluxSpaceBasis[0].size());
208
209 for (label i = 0; i < heatFluxSpaceBasis.size(); ++i)
210 {
211 heatFluxSpaceBasisMatrix.row(i) = Eigen::Map<Eigen::VectorXd>
212 (heatFluxSpaceBasis[i].begin(), heatFluxSpaceBasis[i].size());
213 }
214
215 ITHACAstream::exportMatrix(heatFluxSpaceBasisMatrix, heat_flux_space_basis,
216 "eigen", folderPathPrRb);
217
218 // ###################Kabir: Export the heatFluxSpaceBasis data in order to plot the reconstructed heat flux, ITHACAoutput/projection/HeatFluxSpaceRBF
219
220 if (type == "pod")
221 {
222 Info << "POD basis are not yet implemented, exiting" << endl;
223 exit(10);
224 //List<scalar> massVector(T.boundaryField()[hotSide_ind].size());
225 //forAll (T.boundaryField()[hotSide_ind], faceI)
226 //{
227 // massVector[faceI] = mesh.boundary()[hotSide_ind].magSf()[faceI];
228 //}
229 //List<List<scalar>> tempBasis;
230 //word debugFolder = "./ITHACAoutput/debugParameterizedBasis/";
231 //ITHACAPOD::getModesSVD(heatFluxSpaceBasis, tempBasis, "PODbase", false, false, false, Npod, true);
232 //forAll(heatFluxSpaceBasis, baseI)
233 //{
234 // volScalarField base = list2Field(heatFluxSpaceBasis[baseI], 0.0);
235 // ITHACAstream::exportSolution(base,
236 // std::to_string(1),
237 // debugFolder,
238 // "RBFbase" + std::to_string(baseI + 1));
239 //}
240 //forAll(tempBasis, baseI)
241 //{
242 // volScalarField base = list2Field(tempBasis[baseI], 0.0);
243 // ITHACAstream::exportSolution(base,
244 // std::to_string(1),
245 // debugFolder,
246 // "PODbase" + std::to_string(baseI + 1));
247 //}
248 //heatFluxSpaceBasis = tempBasis;
249 }
250}
251
252void sequentialIHTP::set_gParametrized(word spaceBaseFuncType,
253 scalar shapeParameter_space)
254{
255 volScalarField& T = _T();
256 setSpaceBasis(spaceBaseFuncType, shapeParameter_space);
257 Info << "Using CONSTANT basis in time" << endl;
258 NbasisInTime = 1;
259 NsamplesWindow = 1;
261 gBaseFunctions.resize(Nbasis);
263 forAll(gBaseFunctions, baseI)
264 {
266
267 for (int timeI = 0; timeI < NtimestepsInSequence; timeI++)
268 {
269 gBaseFunctions[baseI][timeI] = heatFluxSpaceBasis[baseI];
270 }
271 }
272 g.resize(timeSteps.size());
273 gWeights.resize(Nbasis);
274 forAll (gWeights, weigthI)
275 {
276 gWeights[weigthI] = 0;
277 }
278 forAll(timeSteps, timeI)
279 {
280 g[timeI].resize(T.boundaryField()[hotSide_ind].size(), 0.0);
281 }
282}
283
284List<List<scalar>> sequentialIHTP::interpolateWeights(List<scalar> Wold,
285 List<scalar> Wnew)
286{
287 M_Assert(Wold.size() == Wnew.size(),
288 "Input weights vectors must have the same size");
289 double t0 = 0;
290 double t1 = NtimeStepsBetweenSamples * deltaTime;
291 List<List<scalar>> Wout;
292 Wout.resize(Wold.size());
293 forAll (Wold, wI)
294 {
295 Wout[wI].resize(NtimeStepsBetweenSamples + 1);
296
297 for (int timeI = 0; timeI < NtimeStepsBetweenSamples + 1; timeI++)
298 {
299 double time = (timeI + 1) * deltaTime;
300 double a = Wold[wI] - (Wnew[wI] - Wold[wI]) / (t1 - t0) * t0;
301 double b = (Wnew[wI] - Wold[wI]) / (t1 - t0);
302 Wout[wI][timeI] = a + b * time;
303 }
304 }
305 return Wout;
306}
307
308void sequentialIHTP::update_gParametrized(List<scalar> weights)
309{
310 M_Assert(weights.size() == Nbasis,
311 "weigths size different from basis functions size");
312 volScalarField& T = _T();
313 label firstTimeI = timeSampleI * NtimeStepsBetweenSamples;
314 List<List<scalar>> interpolatedWeights;
315
316 if (interpolationFlag && !offlineFlag)
317 {
318 if (timeSampleI > 0)
319 {
320 interpolatedWeights = interpolateWeights(gWeightsOld, weights);
321 }
322 }
323
324 int lastTimeStep = firstTimeI + NtimeStepsBetweenSamples + 1;
325 label shortTime = 0;
326
327 for (int timeI = firstTimeI; timeI < lastTimeStep; timeI++)
328 {
329 forAll (T.boundaryField()[hotSide_ind], faceI)
330 {
331 g[timeI][faceI] = 0.0;
332 forAll (weights, weightI)
333 {
334 if (interpolationFlag && !offlineFlag)
335 {
336 if (timeSampleI > 0)
337 {
338 g[timeI][faceI] += interpolatedWeights[weightI][shortTime] *
339 gBaseFunctions[weightI][shortTime][faceI];
340 }
341 else
342 {
343 g[timeI][faceI] += weights[weightI] *
344 gBaseFunctions[weightI][shortTime][faceI];
345 }
346 }
347 else
348 {
349 g[timeI][faceI] += weights[weightI] *
350 gBaseFunctions[weightI][shortTime][faceI];
351 }
352 }
353 }
354 shortTime++;
355 }
356}
357
358volScalarField sequentialIHTP::list2Field(List<scalar> list,
359 scalar innerField)
360{
361 volScalarField& T = _T();
362 fvMesh& mesh = _mesh();
363 volScalarField field(T);
364 ITHACAutilities::assignIF(field, innerField);
365 //Access the mesh information for the boundary
366 const polyPatch& cPatch = mesh.boundaryMesh()[hotSide_ind];
367 //List of cells close to a boundary
368 const labelUList& faceCells = cPatch.faceCells();
369 forAll(cPatch, faceI)
370 {
371 //id of the owner cell having the face
372 label faceOwner = faceCells[faceI] ;
373 field[faceOwner] = list[faceI];
374 }
375 return field;
376}
377
379{
380 fvMesh& mesh = _mesh();
381 Tbasis.resize(0);
382 T0field.resize(0);
383 M_Assert(diffusivity > 0.0, "Call setDiffusivity to set up the diffusivity");
386
387 if (ITHACAutilities::check_file(folderOffline + "/Theta_mat.txt") && force == 0)
388 {
389 Info << "\nOffline already computed." << endl;
390 Info << "Check that the basis used for the parameterized BC are correct (RBF, POD, etc.)"
391 << endl;
392 Theta = ITHACAstream::readMatrix(folderOffline + "Theta_mat.txt");
393 addSol = ITHACAstream::readMatrix(folderOffline + "addSol_mat.txt");
395
396 for (label baseI = 0; baseI < Theta.cols(); baseI++)
397 {
398 Ttime.resize(0);
399 ITHACAstream::read_fields(Ttime, "T" + std::to_string(baseI + 1),
401 Tbasis.append(Ttime.clone());
402 }
403 }
404 else
405 {
406 Info << "\nComputing offline" << endl;
407 Theta.resize(Nbasis, gWeights.size());
408 offlineFlag = 1;
409 Info << "Theta size = " << Theta.rows() << ", " << Theta.cols() << endl;
411
412 for (label baseI = 0; baseI < Theta.cols(); baseI++)
413 {
414 Info << "\n--------------------------------------\n" << endl;
415 Info << "Base " << baseI + 1 << " of " << Theta.cols() << endl;
416 Info << "\n--------------------------------------\n" << endl;
417 restart();
418 Ttime.resize(0);
419 gWeights = Foam::zero();
420 gWeights[baseI] = 1;
421 timeSampleI = 0;
423 solveDirect();
424
425 for (int timeI = 0; timeI < offlineTimestepsSize; timeI++)
426 {
427 volScalarField& T = Ttime[timeI];
429 volScalarField gParametrizedField = list2Field(g[timeI]);
430 ITHACAstream::exportSolution(gParametrizedField,
431 std::to_string(timeSteps[timeI + 1]),
433 "g" + std::to_string(baseI + 1));
434 ITHACAstream::exportSolution(T, std::to_string(timeSteps[timeI + 1]),
436 "T" + std::to_string(baseI + 1));
437 }
438
439 Tbasis.append(Ttime.clone());
440 Tcomp = fieldValueAtThermocouples(Ttime);
441 M_Assert(Tcomp.size() == addSol.size(),
442 "Something wrong in reading values at the observations points");
443
444 for (int i = 0; i < Tcomp.size(); i++)
445 {
446 Theta(i, baseI) = Tcomp(i) + addSol(i);
447 }
448 }
449
450 ITHACAstream::exportMatrix(Theta, "Theta", "eigen", folderOffline);
451 ITHACAstream::exportMatrix(addSol, "addSol", "eigen", folderOffline);
452 }
453
454 Eigen::MatrixXd A = Theta;
455 Eigen::JacobiSVD<Eigen::MatrixXd> svd(A,
456 Eigen::ComputeThinU | Eigen::ComputeThinV);
457 Eigen::MatrixXd singularValues = svd.singularValues();
458 double conditionNumber = singularValues.maxCoeff() / singularValues.minCoeff();
459 Info << "Theta Condition number = " << conditionNumber << endl;
460 ITHACAstream::exportMatrix(singularValues, "ThetaSingularValues", "eigen",
462 Eigen::MatrixXd ThetaTI = Theta * Eigen::MatrixXd::Identity(Theta.rows(),
463 Theta.cols());
464 ITHACAstream::exportMatrix(ThetaTI, "ThetaTI", "eigen",
466 offlineFlag = 0;
467 Info << "\nOffline ENDED" << endl;
468}
469
470void sequentialIHTP::reconstrucT(word outputFolder)
471{
472 Info << "Reconstructing field T" << endl;
473 Ttime.resize(0);
474 Info << "\nExporting solution in the time domain (" <<
475 timeSteps[NtimeStepsBetweenSamples * timeSampleI] << ", " <<
477 "]\n" << endl;
478 restart();
479
480 if (timeSampleI == 0)
481 {
482 ITHACAstream::exportSolution(T0_time[0], std::to_string(timeSteps[0]),
483 outputFolder,
484 "Treconstructed");
485 volScalarField gParametrizedField = list2Field(g[0]);
486 ITHACAstream::exportSolution(gParametrizedField,
487 std::to_string(timeSteps[0]),
488 outputFolder,
489 "gReconstructed");
490 }
491
492 for (int timeI = 0; timeI < NtimeStepsBetweenSamples; timeI++)
493 {
494 volScalarField T = _T.clone();
495 ITHACAutilities::assignIF(T, homogeneousBC);
496 forAll(Tbasis, baseI)
497 {
498 T += gWeights[baseI] * (Tbasis[baseI][timeI] + Tad_time[timeI]);
499 }
500 T += - Tad_time[timeI] + T0_time[timeI];
501 label realTimeStep = timeI + NtimeStepsBetweenSamples * timeSampleI + 1;
502 ITHACAstream::exportSolution(T, std::to_string(timeSteps[realTimeStep]),
503 outputFolder,
504 "Treconstructed");
505 volScalarField gParametrizedField = list2Field(g[realTimeStep - 1]);
506 ITHACAstream::exportSolution(gParametrizedField,
507 std::to_string(timeSteps[realTimeStep]),
508 outputFolder,
509 "gReconstructed");
510 Ttime.append(T.clone());
511 }
512}
513
514Eigen::VectorXd sequentialIHTP::reconstrucT(Eigen::VectorXi cells)
515{
516 Eigen::VectorXd Tout(cells.size());
517 int timeI = NtimeStepsBetweenSamples - 1;
518
519 for (int cellI = 0; cellI < cells.size(); cellI++)
520 {
521 forAll(Tbasis, baseI)
522 {
523 Tout(cellI) += gWeights[baseI] * (Tbasis[baseI][timeI].internalField()[cellI]
524 + Tad_time[timeI].internalField()[cellI]);
525 }
526 Tout(cellI) += - Tad_time[timeI].internalField()[cellI] +
527 T0_time[timeI].internalField()[cellI];
528 }
529
530 return Tout;
531}
532
533void sequentialIHTP::parameterizedBC(word outputFolder,
534 volScalarField initialField)
535{
536 Info << endl << "Using quasilinearity of direct problem ::" << endl;
537 Info << "Using " << linSys_solver << " to solve the linear system" << endl;
538 timeSampleI = 0;
539 List<Eigen::MatrixXd> linSys;
540 linSys.resize(2);
541 linSys[0] = Theta.transpose() * Theta;
542
543 while (timeSampleI < timeSamplesNum)
544 {
545 Info << "\nTime sample " << timeSampleI + 1 << endl;
546 auto t_start = std::chrono::high_resolution_clock::now();
547
548 if (timeSampleI > 0)
549 {
550 reconstrucT("./ITHACAoutput/debugReconstrucT/");
551 initialField = Ttime[NtimeStepsBetweenSamples - 1];
552 }
553
554 solveT0(initialField);
555 TmeasShort = Tmeas.segment(thermocouplesNum * timeSampleI,
557 NsamplesWindow); // Kabir: thermocouplesNum comes from createThermocouples.H inside /u/k/kbakhsha/ITHACA-FV-KF/src/ITHACA_FOMPROBLEMS/sequentialIHTP
558 linSys[1] = Theta.transpose() * (TmeasShort + addSol - T0_vector);
559 Eigen::VectorXd weigths;
560
561 if (linSys_solver == "fullPivLU")
562 {
563 weigths = linSys[0].fullPivLu().solve(linSys[1]);
564 }
565 else if (linSys_solver == "jacobiSvd")
566 {
567 Eigen::JacobiSVD<Eigen::MatrixXd> svd(linSys[0],
568 Eigen::ComputeThinU | Eigen::ComputeThinV);
569 weigths = svd.solve(linSys[1]);
570 }
571 else if (linSys_solver == "householderQr")
572 {
573 weigths = linSys[0].householderQr().solve(linSys[1]);
574 }
575 else if (linSys_solver == "ldlt")
576 {
577 weigths = linSys[0].ldlt().solve(linSys[1]);
578 }
579 else if (linSys_solver == "inverse")
580 {
581 weigths = linSys[0].inverse() * linSys[1];
582 }
583 else if (linSys_solver == "TSVD")
584 {
585 Info << "Using TSVD" << endl;
586 weigths = ITHACAregularization::TSVD(Theta, TmeasShort + addSol - T0_vector,
587 TSVD_filter);
588 }
589 else if (linSys_solver == "Tikhonov")
590 {
591 linSys[0] = Theta;
592 linSys[1] = (TmeasShort + addSol - T0_vector);
593 Eigen::JacobiSVD<Eigen::MatrixXd> svd(linSys[0],
594 Eigen::ComputeThinU | Eigen::ComputeThinV);
595 weigths = ITHACAregularization::Tikhonov(Theta, linSys[1], Tikhonov_filter);
596 }
597 else
598 {
599 Info << "Select a linear system solver in this list:" << endl
600 << "fullPivLU, jacobiSvd, householderQr, ldlt, TSVD, Tikhonov, conjugateGradient"
601 << endl;
602 exit(1);
603 }
604
606 gWeights.resize(weigths.size());
607 forAll(gWeights, weightI)
608 {
609 gWeights[weightI] = weigths(weightI);
610 }
611 Info << "Weights = \n" << gWeights << endl;
613 label verbose = 0;
614 parameterizedBC_postProcess(linSys, weigths, outputFolder, verbose);
615 timeSampleI++;
616 auto t_end = std::chrono::high_resolution_clock::now();
617 double elapsed_time_ms = std::chrono::duration<double, std::milli>
618 (t_end - t_start).count();
619 Info << "CPU time = " << elapsed_time_ms << " milliseconds" << endl << endl;
620 }
621
622 ITHACAstream::exportMatrix(Jlist, "costFunction", "eigen", outputFolder);
623 Info << "End" << endl;
624 Info << endl;
625}
626
628{
629 fvMesh& mesh = _mesh();
630 valueFraction.resize(mesh.boundaryMesh()["coldSide"].size());
631 homogeneousBCcoldSide.resize(mesh.boundaryMesh()["coldSide"].size());
632 Eigen::VectorXd faceCellDist =
634 forAll (valueFraction, faceI)
635 {
636 valueFraction[faceI] = 1 / (1 + (thermalCond / HTC / faceCellDist(faceI)));
637 homogeneousBCcoldSide[faceI] = 0;
638 }
639 refGrad = homogeneousBCcoldSide;
640}
641
643{
644 fvMesh& mesh = _mesh();
645 volScalarField& T = _T();
647 forAll(mesh.boundaryMesh(), patchI)
648 {
649 if (patchI == mesh.boundaryMesh().findPatchID("coldSide"))
650 {
651 ITHACAutilities::assignMixedBC(T, patchI, Tf, refGrad, valueFraction);
652 }
653 else if (patchI == mesh.boundaryMesh().findPatchID("hotSide"))
654 {
655 ITHACAutilities::assignBC(T, patchI, - g[timeI] / thermalCond);
656 }
657 else
658 {
659 ITHACAutilities::assignBC(T, patchI, homogeneousBC);
660 }
661 }
662}
663
664void sequentialIHTP::solveT0(volScalarField initialField)
665{
666 Info << "\nSolving FULL T0 problem" << endl;
668 fvMesh& mesh = _mesh();
669 simpleControl& simple = _simple();
670 fv::options& fvOptions(_fvOptions());
671 volScalarField T0 = _T.clone();
672 Foam::Time& runTime = _runTime();
674 List<scalar> RobinBC = Tf * 0.0;
675 word outputFolder = "./ITHACAoutput/debugT0/";
676 T0 = initialField;
677 T0field.append(T0.clone());
678 T0_time.resize(0);
679 label timeI = 0;
680 forAll(mesh.boundaryMesh(), patchI)
681 {
682 if (patchI == mesh.boundaryMesh().findPatchID("coldSide"))
683 {
684 ITHACAutilities::assignMixedBC(T0, patchI, RobinBC, refGrad,
685 valueFraction);
686 }
687 else
688 {
689 ITHACAutilities::assignBC(T0, patchI, homogeneousBC);
690 }
691 }
692
693 while (runTime.loop())
694 {
695 Info << "Time = " << runTime.timeName() << nl << endl;
696 timeI++;
697
698 while (simple.correctNonOrthogonal())
699 {
700 fvScalarMatrix TEqn
701 (
702 fvm::ddt(T0) - fvm::laplacian(DT * diffusivity, T0)
703 );
704 fvOptions.constrain(TEqn);
705 TEqn.solve();
706 fvOptions.correct(T0);
707 }
708
709 T0_time.append(T0.clone());
710 T0field.append(T0.clone());
711 ITHACAstream::exportSolution(T0, std::to_string(
713 timeI]), outputFolder, "T0");
714 runTime.printExecutionTime(Info);
715 runTime.write();
716 }
717
718 T0_vector = fieldValueAtThermocouples(T0_time);
719 Info << "SolveT0 ENDED\n" << endl;
720}
721
723{
724 word outputFolder = "./ITHACAoutput/modes/";
725 Info << "Computing " << NmodesT0 << " T0 modes" << endl;
727 0, 0, 0,
728 NmodesT0);
729 PtrList<volScalarField> modes = T0modes.toPtrList();
730 forAll(modes, modeI)
731 {
732 ITHACAstream::exportSolution(modes[modeI], std::to_string(modeI + 1),
733 outputFolder, "T0modes");
734 }
735 Info << "T0 modes COMPUTED\n" << endl;
736}
737
739{
740 Info << "\n*****************************************************" << endl;
741 Info << "Computing projection matrices" << endl;
742 fvMesh& mesh = _mesh();
743 simpleControl& simple = _simple();
744 fv::options& fvOptions(_fvOptions());
745 volScalarField T0 = _T.clone();
746 Foam::Time& runTime = _runTime();
748 List<scalar> RobinBC = Tf * 0.0;
749 forAll(mesh.boundaryMesh(), patchI)
750 {
751 if (patchI == mesh.boundaryMesh().findPatchID("coldSide"))
752 {
753 ITHACAutilities::assignMixedBC(T0, patchI, RobinBC, refGrad,
754 valueFraction);
755 }
756 else
757 {
758 ITHACAutilities::assignBC(T0, patchI, homogeneousBC);
759 }
760 }
761 Eigen::SparseMatrix<double> T0implicitMatrix;
762 Eigen::SparseMatrix<double> T0explicitMatrix;
764 fvScalarMatrix Teq(fvm::ddt(T0) - fvm::laplacian(DT * diffusivity, T0));
765 Eigen::VectorXd b;
766 Foam2Eigen::fvMatrix2Eigen(Teq, T0implicitMatrix, b);
767 T0modes.toEigen();
768 T0implicitMatrix_red = T0modes.EigenModes[0].transpose()
769 * T0implicitMatrix * T0modes.EigenModes[0];
770 T0explicitMatrix_red = T0modes.EigenModes[0].transpose()
771 * b.asDiagonal() * T0modes.EigenModes[0];
772 Info << "Projection matrices COMPUTED\n" << endl;
773}
774
776{
779 Info << "Computing direct problem projection matrices" << endl;
780 int internalFieldSize = Tbasis[0][0].internalField().size();
781 Eigen::MatrixXd Tbasis_Eigen(internalFieldSize, Nbasis);
782 Eigen::VectorXd Tad_Eigen =
784 PtrList<volScalarField> Tbasis_lastTime;
785 M_Assert(Tbasis[0].size() == NtimeStepsBetweenSamples,
786 "The basis for the direct problem have wrong dimention in time");
787 forAll(Tbasis, baseI)
788 {
789 volScalarField temp = Tbasis[baseI][NtimeStepsBetweenSamples - 1]
790 + Tad_time[NtimeStepsBetweenSamples - 1];
791 Tbasis_lastTime.append(temp.clone());
792 }
793 Tbasis_projectionMat = T0modes.project(Tbasis_lastTime);
794 Tad_projected = T0modes.project(Tad_time[NtimeStepsBetweenSamples - 1]);
795}
796
798{
799 int Ncells = magicPoints.size();
800 M_Assert(Ncells > 0, "Set the number of magic points");
801 int lastTimestepID = NtimeStepsBetweenSamples - 1;
802 pointsReconstructMatrix.resize(Ncells, NmodesT0);
803
804 for (int cellI = 0; cellI < Ncells; cellI++)
805 {
806 pointsReconstructMatrix.row(cellI) =
807 T0modes.EigenModes[0].row(magicPoints[cellI]);
808 }
809
812}
813
815{
817 Info << "Computing the offline part for the projection error" << endl;
818 //TODO You can consider all modes when computing the error and then
819 //choose the right ammount of modes based on the behaviour of the error
820 int lastTimestepID = NtimeStepsBetweenSamples - 1;
821 projectionErrorTbasis.resize(0);
822 word outputFolder = "./ITHACAoutput/projectionError";
823 forAll(Tbasis, baseI)
824 {
825 volScalarField base = Tbasis[baseI][lastTimestepID];
826 volScalarField baseProj(base);
827 baseProj = T0modes.projectSnapshot(base, NmodesT0);//, "L2");
828 volScalarField temp = base - baseProj;
829 projectionErrorTbasis.append(temp.clone());
831 std::to_string(baseI + 1),
832 outputFolder, "projectionErrorTbasis");
833 }
834 projectionErrorTad.resize(0);
835 volScalarField TadProj(Tbasis[0][lastTimestepID]);
836 TadProj = T0modes.projectSnapshot(Tad_time[lastTimestepID], NmodesT0);//, "L2");
837 volScalarField temp(Tad_time[lastTimestepID] - TadProj);
838 projectionErrorTad.append(temp.clone());
840 outputFolder, "projectionErrorTad");
841 //forAll(Tbasis, baseI)
842 //{
843 // volScalarField base = Tbasis[baseI][lastTimestepID];
844 // volScalarField baseProj(base);
845 // T0modes.projectSnapshot(base, baseProj, NmodesT0, "L2");
846 // volScalarField basePerp = base - baseProj;
847 // projectionErrorTbasis(baseI) = ITHACAutilities::L2Norm(basePerp);
848 // Info << "Projection error Tbase["<< baseI << "] = " << projectionErrorTbasis(baseI) << endl;
849 //}
850 //volScalarField TadProj(Tad_time[lastTimestepID]);
851 //T0modes.projectSnapshot(Tad_time[lastTimestepID], TadProj, NmodesT0, "L2");
852 //volScalarField TadPerp = Tad_time[lastTimestepID] - TadProj;
853 //projectionErrorTad = ITHACAutilities::L2Norm(TadPerp);
854 //Info << "Projection error Tad = " << projectionErrorTad << endl;
855}
856
857void sequentialIHTP::T0offline(int NmagicPoints)
858{
859 getT0modes();
860 findMagicPoints(NmagicPoints);
861 projectT0();
865}
866
868{
869 Info << "Solving additional problem" << endl;
871 fvMesh& mesh = _mesh();
872 simpleControl& simple = _simple();
873 fv::options& fvOptions(_fvOptions());
874 volScalarField Tad = _T.clone();
875 Foam::Time& runTime = _runTime();
877 Tad_time.resize(0);
878 ITHACAutilities::assignIF(Tad, homogeneousBC);
879 label timeI = 0;
880 assignDirectBC(timeI);
881 List<scalar> RobinBC = - Tf;
882 forAll(mesh.boundaryMesh(), patchI)
883 {
884 if (patchI == mesh.boundaryMesh().findPatchID("coldSide"))
885 {
886 ITHACAutilities::assignMixedBC(Tad, patchI, RobinBC, refGrad, valueFraction);
887 }
888 else
889 {
890 ITHACAutilities::assignBC(Tad, patchI, homogeneousBC);
891 }
892 }
893
894 while (runTime.loop())
895 {
896 Info << "Time = " << runTime.timeName() << nl << endl;
897 timeI++;
898 assignDirectBC(timeI);
899 RobinBC = - Tf;
900 forAll(mesh.boundaryMesh(), patchI)
901 {
902 if (patchI == mesh.boundaryMesh().findPatchID("coldSide"))
903 {
904 ITHACAutilities::assignMixedBC(Tad, patchI, RobinBC, refGrad, valueFraction);
905 }
906 else
907 {
908 ITHACAutilities::assignBC(Tad, patchI, homogeneousBC);
909 }
910 }
911
912 while (simple.correctNonOrthogonal())
913 {
914 fvScalarMatrix TEqn
915 (
916 fvm::ddt(Tad) - fvm::laplacian(DT * diffusivity, Tad)
917 );
918 fvOptions.constrain(TEqn);
919 TEqn.solve();
920 fvOptions.correct(Tad);
921 }
922
923 Tad_time.append(Tad.clone());
924 ITHACAstream::exportSolution(Tad, std::to_string(timeSteps[timeI]),
926 "Tad");
927 runTime.printExecutionTime(Info);
928 runTime.write();
929 }
930
931 Info << "Tad_time.size = " << Tad_time.size() << endl;
932 Info << "Ntime = " << Ntimes << endl;
933 addSol = fieldValueAtThermocouples(Tad_time);
934 Info << "END \n" << endl;
935}
936
938{
939 if (offlineFlag)
940 {
942 }
943 else
944 {
945 restart();
946 }
947
948 M_Assert(diffusivity > 1e-36, "Set the diffusivity value");
949 volScalarField& T = _T();
951
952 if (offlineFlag)
953 {
954 ITHACAutilities::assignIF(T, homogeneousBC);
955 }
956
957 simpleControl& simple = _simple();
958 Foam::Time& runTime = _runTime();
959 fv::options& fvOptions(_fvOptions());
960 label timeI = 0;
961 Ttime.resize(0);
962
963 while (runTime.loop())
964 {
965 Info << "Time = " << runTime.timeName() << nl << endl;
966 timeI++;
967 assignDirectBC(timeI);
968
969 while (simple.correctNonOrthogonal())
970 {
971 fvScalarMatrix TEqn
972 (
973 fvm::ddt(T) - fvm::laplacian(DT * diffusivity, T)
974 );
975 fvOptions.constrain(TEqn);
976 TEqn.solve();
977 fvOptions.correct(T);
978 }
979
980 Ttime.append(T.clone());
981 runTime.printExecutionTime(Info);
982 runTime.write();
983 }
984
985 Info << "Direct computation ENDED" << endl;
986}
987
989{
990 Info << "Defining positions of thermocouples" << endl;
991
993 {
994 word fileName = "./thermocouplesCellsID";
995
996 if (ITHACAutilities::check_file(fileName + "_mat.txt"))
997 {
998 Info << "Reading thermocouples cells from file" << endl;
999 Eigen::MatrixXi TCmatrix = ITHACAstream::readMatrix(fileName + "_mat.txt").cast
1000 <int> ();
1001 thermocouplesCellID = Foam2Eigen::EigenMatrix2List(TCmatrix);
1002 }
1003 else
1004 {
1005 Info << "Defining positions of thermocouples" << endl;
1006 fvMesh& mesh = _mesh();
1007 volScalarField& T = _T();
1008 thermocouplesCellID.resize(thermocouplesPos.size());
1009 forAll(thermocouplesPos, tcI)
1010 {
1011 thermocouplesCellID[tcI] = mesh.findCell(thermocouplesPos[tcI]);
1012 }
1013 volScalarField thermocouplesField(T);
1014 ITHACAutilities::assignIF(thermocouplesField, homogeneousBC);
1015 forAll(thermocouplesCellID, tcI)
1016 {
1017 thermocouplesField.ref()[thermocouplesCellID[tcI]] = 1;
1018 }
1019 ITHACAstream::exportSolution(thermocouplesField, "1",
1020 "./ITHACAoutput/thermocouplesField/",
1021 "thermocouplesField,");
1022 Eigen::MatrixXi thermocouplesCellID_eigen = Foam2Eigen::List2EigenMatrix(
1023 thermocouplesCellID);
1024 ITHACAstream::exportMatrix(thermocouplesCellID_eigen, fileName,
1025 "eigen", "./");
1026 }
1027
1030 forAll(samplingTime, timeI)
1031 {
1032 samplingTime[timeI] = timeSamplesT0 + timeI * timeSamplesDeltaT;
1033 }
1037 }
1038 else
1039 {
1040 WarningInFunction << "readThermocouples function called twice." << endl;
1041 WarningInFunction << "I am not doing the second reading." << endl;
1042 }
1043}
1044
1046 volScalarField& field)
1047{
1048 if (!thermocouplesRead)
1049 {
1051 }
1052
1053 fvMesh& mesh = _mesh();
1054 dictionary interpolationDict =
1055 mesh.solutionDict().subDict("interpolationSchemes");
1056 autoPtr<Foam::interpolation<scalar>> fieldInterp =
1057 Foam::interpolation<scalar>::New(interpolationDict, field);
1058 Eigen::VectorXd fieldInt;
1059 fieldInt.resize(thermocouplesPos.size());
1060 forAll(thermocouplesPos, tcI)
1061 {
1062 fieldInt(tcI) = fieldInterp->interpolate(thermocouplesPos[tcI],
1063 thermocouplesCellID[tcI]);
1064 }
1065 return fieldInt;
1066}
1067
1069 PtrList<volScalarField> fieldList, label fieldI)
1070{
1071 Eigen::VectorXd fieldInt = fieldValueAtThermocouples(fieldList[fieldI]);
1072 return fieldInt;
1073}
1074
1076 PtrList<volScalarField> fieldList)
1077{
1078 Eigen::VectorXd fieldInt;
1079
1080 if ( fieldList.size() == Ntimes + 1 )
1081 {
1082 Info << "\n Sampling for ALL sampling times \n\n" << endl;
1083 fieldInt.resize(timeSamplesNum * thermocouplesNum);
1084 forAll(samplingSteps, sampleTimeI)
1085 {
1086 fieldInt.segment(sampleTimeI * thermocouplesNum, thermocouplesNum) =
1087 fieldValueAtThermocouples(fieldList, samplingSteps[sampleTimeI]);
1088 }
1089 }
1090 else if ( fieldList.size() == NtimeStepsBetweenSamples )
1091 {
1092 Info << "\nField size = " << fieldList.size() <<
1093 ".\nSampling ONLY the last timestep\n\n" << endl;
1094 fieldInt =
1096 }
1097 else
1098 {
1099 Info << "The input fieldList of sequentialIHTP::fieldValueAtThermocouples can have size Ntimes + 1 (="
1100 << Ntimes + 1 << ") or\n";
1101 Info << " NtimeStepsBetweenSamples (=" << NtimeStepsBetweenSamples <<
1102 ") but has size " << fieldList.size() << endl;
1103 Info << "Exiting." << endl;
1104 exit(23);
1105 }
1106
1107 Info << "\nSampling done \n" << endl;
1108 return fieldInt;
1109}
1110
1111
1113{
1114 Time& runTime = _runTime();
1115 instantList Times = runTime.times();
1116 runTime.setTime(Times[1], 0);
1117 _simple.clear();
1118 _T.clear();
1119 Foam::fvMesh& mesh = _mesh();
1120 _simple = autoPtr<simpleControl>
1121 (
1122 new simpleControl
1123 (
1124 mesh
1125 )
1126 );
1127 _T = autoPtr<volScalarField>
1128 (
1129 new volScalarField
1130 (
1131 IOobject
1132 (
1133 "T",
1134 runTime.timeName(),
1135 mesh,
1136 IOobject::MUST_READ,
1137 IOobject::AUTO_WRITE
1138 ),
1139 mesh
1140 )
1141 );
1142 Info << "Ready for new computation" << endl;
1143}
1144
1146{
1147 Info << "Setting endTime to offlineEndTime" << endl;
1148 restart();
1149 Time& runTime = _runTime();
1150 instantList Times = runTime.times();
1151 runTime.setTime(0.0, 0);
1152 runTime.setEndTime(offlineEndTime);
1153 Info << "Ready for new offline computation" << endl;
1154}
1155
1157{
1158 Info << "Setting endTime to offlineEndTime" << endl;
1159 restart();
1160 Time& runTime = _runTime();
1161 instantList Times = runTime.times();
1162 runTime.setTime(0.0, 0);
1163 runTime.setEndTime(timeSamplesDeltaT);
1164 Info << "Ready for new T0 computation" << endl;
1165}
1166
1168{
1169 scalar EPSILON = 2e-16;
1170 label deltaTimeQuotient = std::floor(timeSamplesDeltaT / deltaTime);
1171 //Info << "debug: deltaTimeQuotient= " <<deltaTimeQuotient<< endl;
1172 //Info << "debug: timeSamplesDeltaT= " <<timeSamplesDeltaT<< endl;
1173 //Info << "debug: deltaTime= " <<deltaTime<< endl;
1174 M_Assert(std::fabs(timeSamplesDeltaT / deltaTime - std::trunc(
1175 timeSamplesDeltaT / deltaTime)) < EPSILON,
1176 "timeSamplesDeltaT should be a multiple of deltaTime");
1177 label n0 = (timeSamplesT0 - startTime) / deltaTime;
1178 M_Assert(n0 > 0, "First sampling step cannot be 0");
1179 //Info << "debug: n0 = " << n0 << endl;
1180 //Info << "debug: (timeSamplesT0 - startTime) / deltaTime = " << (timeSamplesT0 - startTime) / deltaTime << endl;
1181 M_Assert(std::fabs(n0 * deltaTime - timeSamplesT0) < EPSILON,
1182 "The first sampling time must coincide with a simulation timestep");
1183 scalar samplingEndTime = timeSamplesDeltaT * (timeSamplesNum - 1) +
1185 //Info << "debug: samplingEndTime = " << samplingEndTime << endl;
1186 //Info << "debug: EndTime = " << endTime << endl;
1187 M_Assert(!(endTime + EPSILON < samplingEndTime
1188 && std::fabs(endTime - samplingEndTime) > EPSILON),
1189 "The samplingEndTime cannot be later than the symulation endTime");
1191 forAll(samplingTime, sampleI)
1192 {
1193 samplingSteps[sampleI] = n0 + sampleI * deltaTimeQuotient;
1194 }
1195 //Info << "debug: samplingSteps = " << samplingSteps << endl;
1196}
1197
1198void sequentialIHTP::parameterizedBC_postProcess(
1199 List<Eigen::MatrixXd> linSys, Eigen::VectorXd weigths, word outputFolder,
1200 label verbose)
1201{
1202 Eigen::JacobiSVD<Eigen::MatrixXd> svd(Theta,
1203 Eigen::ComputeThinU | Eigen::ComputeThinV);
1204 Eigen::MatrixXd singVal = svd.singularValues();
1205 ITHACAstream::exportMatrix(singVal, "singularValues", "eigen", outputFolder);
1206
1207 if (verbose)
1208 {
1209 // Printing outputs at screen
1210 Info << "Singular values of Theta.transpose() * Theta are " << endl;
1211 Info << svd.singularValues() << endl;
1212 Info << "weigths = " << endl;
1213 Info << weigths << endl;
1214 Info << "linSys[1] = " << endl;
1215 Info << linSys[1] << endl;
1216 Info << "Theta = " << endl;
1217 Info << Theta << endl;
1218 residual = linSys[0] * weigths - linSys[1];
1219 //Info << "Residual = " << endl;
1220 //Info << residual << endl;
1221 Info << "Residual 2-norm = " << endl;
1222 Info << residual.squaredNorm() << endl;
1223 Info << "\n addSol = " << endl;
1224 Info << addSol << endl;
1225 Info << "T0_vector = " << endl;
1226 Info << T0_vector << endl;
1227 Info << "Tmeas = " << endl;
1228 Info << Tmeas << endl;
1229 }
1230
1231 reconstrucT(outputFolder);
1232 Tcomp = fieldValueAtThermocouples(Ttime);
1233 Info << "Tcomp = \n" << Tcomp.transpose() << endl;
1234 Info << "TmeasShort = \n" << TmeasShort.transpose() << endl;
1235 J = 0.5 * Foam::sqrt((Tcomp - TmeasShort).dot(Tcomp - TmeasShort));
1236 Info << "J = " << J << endl;
1237 Jlist.conservativeResize(Jlist.size() + 1);
1238 Jlist(Jlist.size() - 1) = J;
1239}
1240
1242{
1243 M_Assert(NmagicPoints > 0, "Set number of magic points");
1244 magicPoints.clear();
1245 M_Assert(NmagicPoints <= NmodesT0,
1246 "Number of magic points bigger than number of modes");
1247 Eigen::MatrixXd A;
1248 Eigen::VectorXd b;
1249 Eigen::VectorXd c;
1250 Eigen::VectorXd r;
1251 Eigen::VectorXd rho(1);
1252 Eigen::MatrixXd MatrixModes = T0modes.toEigen()[0];
1253 label ind_max, c1;
1254 double max = MatrixModes.cwiseAbs().col(0).maxCoeff(&ind_max, &c1);
1255 rho(0) = max;
1256 magicPoints.append(ind_max);
1257 Eigen::MatrixXd U = MatrixModes.col(0);
1258 Eigen::SparseMatrix<double> P;
1259 P.resize(MatrixModes.rows(), 1);
1260 P.insert(ind_max, 0) = 1;
1261
1262 for (label i = 1; i < NmagicPoints; i++)
1263 {
1264 A = P.transpose() * U;
1265 b = P.transpose() * MatrixModes.col(i);
1266 c = A.fullPivLu().solve(b);
1267 r = MatrixModes.col(i) - U * c;
1268 max = r.cwiseAbs().maxCoeff(&ind_max, &c1);
1269 P.conservativeResize(MatrixModes.rows(), i + 1);
1270 P.insert(ind_max, i) = 1;
1271 U.conservativeResize(MatrixModes.rows(), i + 1);
1272 U.col(i) = MatrixModes.col(i);
1273 rho.conservativeResize(i + 1);
1274 rho(i) = max;
1275 magicPoints.append(ind_max);
1276 }
1277
1278 Info << "magicPoints:\n" << magicPoints << endl;
1279}
static Eigen::Matrix< type_matrix, Eigen::Dynamic, Eigen::Dynamic > List2EigenMatrix(List< type_matrix > list)
Convert a Foam List into an Eigen matrix with one column.
static List< type_matrix > EigenMatrix2List(Eigen::Matrix< type_matrix, Eigen::Dynamic, Eigen::Dynamic > matrix)
Convert an Eigen matrix with one column into a Foam List.
static Eigen::MatrixXd field2Eigen(GeometricField< Type, PatchField, GeoMesh > &field)
Convert a vector OpenFOAM field into an Eigen Vector.
static void fvMatrix2Eigen(fvMatrix< type_foam_matrix > foam_matrix, type_A &A, type_B &b)
Convert a FvMatrix OpenFOAM matrix (Linear System) into a Eigen Matrix A and a source vector b.
Class for the definition of some general parameters, the parameters must be defined from the file ITH...
IOdictionary * ITHACAdict
Dictionary for input objects from file.
static ITHACAparameters * getInstance()
Gets an instance of ITHACAparameters, to be used if the instance is already existing.
bool offline
Boolean variable, it is 1 if the Offline phase has already been computed, else 0.
IOdictionary * ITHACAdict
dictionary to store input output infos
autoPtr< argList > _args
argList
bool podex
Boolean variable, it is 1 if the POD has already been computed, else 0.
virtual void readThermocouples()
Identifies in the mesh the cells corresponding to the termocouples locations.
void parameterizedBCoffline(bool force=0)
Performs offline computation for the parameterized BC method, if the offline directory "".
Eigen::MatrixXd T0explicitMatrix_red
T0 reduced explicit matrix.
label timeSamplesNum
Number of time samples (filled in createThermocouples.H).
label NbasisInTime
Number of basis in time.
label coldSide_ind
Index of the coldSide patch.
Eigen::VectorXd pointTad_reconstructed
Reconstruction of Tsd at the magic points.
scalar diffusivity
Diffusivity value.
double HTC
Heat transfer coefficient [W/(m2 K)].
scalar timeSamplesDeltaT
Time interval in between samples (read from thermocouplesDict).
void restartT0()
Restart fields.
int NmodesT0
Number of POD modes.
void restartOffline()
Restart fields.
int thermocouplesNum
Number of thermocouples.
void T0offline(int NmagicPoints)
Assemble all the matrices required in the online phase.
dimensionedScalar DT
Dummy thermal diffusivity with unitary value.
volScalarModes T0modes
List of POD modes.
Eigen::VectorXd Jlist
List of cost funtions [K^2].
label hotSide_ind
Index of the hotSide patch.
Eigen::MatrixXd Tbasis_projectionMat
Projection of the Tbasis on the reduced space.
label timeSampleI
Time sample index.
Eigen::VectorXd Tad_projected
Projection of Tad on the reduced space.
Eigen::MatrixXd pointsReconstructMatrix
Matrix that reconstruct some points into the full order space.
label NtimestepsInSequence
Number of timesteps considered in each acquisition sequence.
List< scalar > gWeightsOld
Weights of the parameterization.
void reconstrucT(word outputFolder)
Reconstructs the temperature field using superposition of effects.
PtrList< volScalarField > projectionErrorTad
L2 norm of the projection error of Tad on the T0 modes.
Eigen::MatrixXd T0implicitMatrix_red
T0 reduced implicit matrix.
List< List< scalar > > interpolateWeights(List< scalar > Wold, List< scalar > Wnew)
double thermalCond
Thermal conductivity [W/(m K)].
PtrList< volScalarField > projectionErrorTbasis
L2 norm of the projection error of Tbasis on the T0 modes.
void findMagicPoints(int NmagicPoints)
Find the points at with the projection error is computed.
List< List< scalar > > heatFluxSpaceBasis
Heat flux space basis.
PtrList< volScalarField > T0field
List of snapshots for the T0 solutions.
word folderOffline
Folder where the offline solutions are saved.
List< List< List< scalar > > > gBaseFunctions
Bases of the heat flux.
scalar startTime
Time discretization (filled in the constructor).
void solveAdditional()
Set BC and IF of the additional problem for the parameterized heat flux.
void projectionErrorOffline()
Compute the L2 norm of the projection error for each Tbasis and Tad.
autoPtr< volScalarField > _T
Temperature field.
List< label > magicPoints
Magic points for the T0 projection error estimation.
void update_gParametrized(List< scalar > weights)
Update the boundary condition g when g is parameterized.
virtual void solveT0(volScalarField initialField)
Solve the T0 problem.
void sampling2symulationTime()
Fills the vector samplingSteps which contains the timesteps at which the measurements are taken.
label NbasisInSpace
Number of basis in space.
List< scalar > samplingTime
List of times at which the measurements are acquired (this List is filled by readThermocouples()).
bool thermocouplesRead
1 if readThermocouples() was called, 0 elsewise
double J
Cost funtion [K^2].
autoPtr< Time > _runTime
Time.
void set_gParametrized(word spaceBaseFuncType, scalar shapeParameter_space)
Set parameterized heat flux defining the basis.
Eigen::VectorXd residual
Parametrized BC.
volScalarField list2Field(List< scalar > list, scalar innerField=0.0)
Convert list of boundary heat flux into field.
scalar offlineEndTime
End time for the ofline computation.
void setDiffusivity(scalar _diff)
Set diffusivity.
void projectT0()
Project T0 matrices onto the reduced spaced.
void projectDirectOntoT0()
Assemble the matrices to go from the gWeights to the T0 reduced space.
autoPtr< fvMesh > _mesh
Mesh.
scalar timeSamplesT0
First sampling time (read from thermocouplesDict).
List< List< scalar > > g
Heat flux at hotSide.
List< label > samplingSteps
List of timesteps at which measurements are available.
Eigen::VectorXd fieldValueAtThermocouples(volScalarField &field)
Interpolates the field value at the thermocouples points NOTE: do NOT call whe field is an element of...
label NtimeStepsBetweenSamples
Number of timesteps between two samples.
label offlineTimestepsSize
Number of timestep to solve for during offline phase.
autoPtr< simpleControl > _simple
simpleControl
label Nbasis
Number of basis.
autoPtr< fv::options > _fvOptions
fvOptions
virtual void assignDirectBC(label timeI)
Set BC of the direct problem.
Eigen::MatrixXd pointTbasis_reconstructionMat
Matrix that reconstructs the Tbasis at the magic points.
void solveDirect()
Solve direct problem.
label NsamplesWindow
Number of samples considered in the offline phase.
void set_valueFraction()
Set valueFraction list values for Robin condition.
void pointProjectionOffline()
Assemble the matrix pointsProjectionMatrix to project some points on the reduced basis space.
List< scalar > gWeights
Weights of the parameterization.
void setSpaceBasis(word type, scalar shapeParameter, label Npod=0)
Define the base functions used for the parametrization of g.
void getT0modes()
Compute T0 modes prome snapshots.
void restart()
Restart temperature field.
void getModes(PtrList< GeometricField< Type, PatchField, GeoMesh > > &snapshots, PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, word fieldName, bool podex, bool supex, bool sup, label nmodes, bool correctBC)
Computes the bases or reads them for a field.
Definition ITHACAPOD.C:93
Eigen::VectorXd Tikhonov(Eigen::MatrixXd A, Eigen::MatrixXd b, double regularizationParameter)
Truncated Singular Value regularization.
Eigen::VectorXd TSVD(Eigen::MatrixXd A, Eigen::MatrixXd b, int filter)
Truncated Singular Value regularization.
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 exportMatrix(Eigen::Matrix< T, -1, dim > &matrix, word Name, word type, word folder)
Export the reduced matrices in numpy (type=python), matlab (type=matlab) and txt (type=eigen) format ...
List< Eigen::MatrixXd > readMatrix(word folder, word mat_name)
Read a three dimensional matrix from a txt file in Eigen format.
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.
void assignMixedBC(GeometricField< Type, fvPatchField, volMesh > &field, label BC_ind, List< Type > &value, List< Type > &grad, List< scalar > &valueFrac)
Assign value of a boundary condition of type "mixed".
void assignIF(GeometricField< Type, fvPatchField, volMesh > &s, Type value)
Assign internal field.
bool check_pod()
Check if the POD data folder "./ITHACAoutput/POD" exists.
bool check_off()
Check if the offline data folder "./ITHACAoutput/Offline" exists.
void assignBC(GeometricField< scalar, fvPatchField, volMesh > &s, label BC_ind, double value)
Assign uniform Boundary Condition to a volScalarField.
bool check_file(std::string fileName)
Function that returns true if a file exists.
Eigen::VectorXd boudaryFaceToCellDistance(fvMesh &mesh, label BC_ind)
Compute the distance between the boundary face center and the boundary cell center.
Header file of the sequentialIHTP class.