/*---------------------------------------------------------------------------*\ ██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗ ██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║ ██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║ ██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝ ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝ * In real Time Highly Advanced Computational Applications for Finite Volumes * Copyright (C) 2017 by the ITHACA-FV authors ------------------------------------------------------------------------------- License This file is part of ITHACA-FV ITHACA-FV is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. ITHACA-FV is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with ITHACA-FV. If not, see . Description Example of model reduction problem using the DEIM for a Heat Transfer Problem SourceFiles 09DEIM_ROM.C \*---------------------------------------------------------------------------*/ #include "fvCFD.H" #include "IOmanip.H" #include "fvOptions.H" #include "simpleControl.H" #include "ITHACAutilities.H" #include "Foam2Eigen.H" #include #include "fvMeshSubset.H" #include "ITHACAstream.H" #include "ITHACAPOD.H" #include "EigenFunctions.H" #include "DEIM.H" #include #include #include #include "laplacianProblem.H" class DEIM_function : public DEIM { using DEIM::DEIM; public: static fvScalarMatrix evaluate_expression(volScalarField& T, Eigen::MatrixXd mu) { volScalarField yPos = T.mesh().C().component(vector::Y).ref(); volScalarField xPos = T.mesh().C().component(vector::X).ref(); volScalarField nu(T); for (auto i = 0; i < nu.size(); i++) { nu[i] = std::exp(- 2 * std::pow(xPos[i] - mu(0) - 1, 2) - 2 * std::pow(yPos[i] - mu(1) - 0.5, 2)) + 1; } nu.correctBoundaryConditions(); fvScalarMatrix TiEqn22 ( fvm::laplacian(nu, T, "Gauss linear") ); return TiEqn22; } Eigen::MatrixXd onlineCoeffsA(Eigen::MatrixXd mu) { Eigen::MatrixXd theta(magicPointsAcol().size(), 1); fvScalarMatrix Aof = evaluate_expression(fieldA(), mu); Eigen::SparseMatrix Mr; Eigen::VectorXd br; Foam2Eigen::fvMatrix2Eigen(Aof, Mr, br); for (int i = 0; i < magicPointsAcol().size(); i++) { int ind_row = localMagicPointsArow[i] + xyz_Arow()[i] * fieldA().size(); int ind_col = localMagicPointsAcol[i] + xyz_Acol()[i] * fieldA().size(); theta(i) = Mr.coeffRef(ind_row, ind_col); } return theta; } Eigen::MatrixXd onlineCoeffsB(Eigen::MatrixXd mu) { Eigen::MatrixXd theta(magicPointsB().size(), 1); fvScalarMatrix Aof = evaluate_expression(fieldB(), mu); Eigen::SparseMatrix Mr; Eigen::VectorXd br; Foam2Eigen::fvMatrix2Eigen(Aof, Mr, br); for (int i = 0; i < magicPointsB().size(); i++) { int ind_row = localMagicPointsB[i] + xyz_B()[i] * fieldB().size(); theta(i) = br(ind_row); } return theta; } PtrList fieldsA; autoPtr fieldA; autoPtr fieldB; PtrList fieldsB; }; class DEIMLaplacian: public laplacianProblem { public: explicit DEIMLaplacian(int argc, char* argv[]) : laplacianProblem(argc, argv), nu(_nu()), S(_S()), T(_T()) { fvMesh& mesh = _mesh(); ITHACAdict = new IOdictionary ( IOobject ( "ITHACAdict", "./system", mesh, IOobject::MUST_READ, IOobject::NO_WRITE ) ); NTmodes = readInt(ITHACAdict->lookup("N_modes_T")); NmodesDEIMA = readInt(ITHACAdict->lookup("N_modes_DEIM_A")); NmodesDEIMB = readInt(ITHACAdict->lookup("N_modes_DEIM_B")); } volScalarField& nu; volScalarField& S; volScalarField& T; DEIM_function* DEIMmatrice; PtrList Mlist; Eigen::MatrixXd ModesTEig; std::vector ReducedMatricesA; std::vector ReducedVectorsB; int NTmodes; int NmodesDEIMA; int NmodesDEIMB; double time_full; double time_rom; void OfflineSolve(Eigen::MatrixXd par, word Folder) { if (offline) { ITHACAstream::read_fields(Tfield, T, "./ITHACAoutput/Offline/"); } else { for (int i = 0; i < par.rows(); i++) { fvScalarMatrix Teqn = DEIMmatrice->evaluate_expression(T, par.row(i)); Teqn.solve(); Mlist.append((Teqn).clone()); ITHACAstream::exportSolution(T, name(i + 1), "./ITHACAoutput/" + Folder); Tfield.append((T).clone()); } } }; void OnlineSolveFull(Eigen::MatrixXd par, word Folder) { auto t1 = std::chrono::high_resolution_clock::now(); auto t2 = std::chrono::high_resolution_clock::now(); auto time_span = std::chrono::duration_cast> (t2 - t1); time_full = 0; for (int i = 0; i < par.rows(); i++) { fvScalarMatrix Teqn = DEIMmatrice->evaluate_expression(T, par.row(i)); t1 = std::chrono::high_resolution_clock::now(); Teqn.solve(); t2 = std::chrono::high_resolution_clock::now(); time_span = std::chrono::duration_cast> (t2 - t1); time_full += time_span.count(); ITHACAstream::exportSolution(T, name(i + 1), "./ITHACAoutput/" + Folder); Tfield.append((T).clone()); } }; void PODDEIM() { PODDEIM(NTmodes, NmodesDEIMA, NmodesDEIMB); } void PODDEIM(int NmodesT, int NmodesDEIMA, int NmodesDEIMB) { DEIMmatrice = new DEIM_function(Mlist, NmodesDEIMA, NmodesDEIMB, "T_matrix"); fvMesh& mesh = const_cast(T.mesh()); // Differential Operator DEIMmatrice->fieldA = autoPtr(new volScalarField( DEIMmatrice->generateSubmeshMatrix(2, mesh, T))); DEIMmatrice->fieldB = autoPtr(new volScalarField( DEIMmatrice->generateSubmeshVector(2, mesh, T))); // Source Terms ModesTEig = Foam2Eigen::PtrList2Eigen(Tmodes); ModesTEig.conservativeResize(ModesTEig.rows(), NmodesT); ReducedMatricesA.resize(NmodesDEIMA); ReducedVectorsB.resize(NmodesDEIMB); for (int i = 0; i < NmodesDEIMA; i++) { ReducedMatricesA[i] = ModesTEig.transpose() * DEIMmatrice->MatrixOnlineA[i] * ModesTEig; } for (int i = 0; i < NmodesDEIMB; i++) { ReducedVectorsB[i] = ModesTEig.transpose() * DEIMmatrice->MatrixOnlineB; } }; void OnlineSolve(Eigen::MatrixXd par_new, word Folder) { auto t1 = std::chrono::high_resolution_clock::now(); auto t2 = std::chrono::high_resolution_clock::now(); auto time_span = std::chrono::duration_cast> (t2 - t1); time_rom = 0; for (int i = 0; i < par_new.rows(); i++) { // solve t1 = std::chrono::high_resolution_clock::now(); Eigen::MatrixXd thetaonA = DEIMmatrice->onlineCoeffsA(par_new.row(i)); Eigen::MatrixXd thetaonB = DEIMmatrice->onlineCoeffsB(par_new.row(i)); Eigen::MatrixXd A = EigenFunctions::MVproduct(ReducedMatricesA, thetaonA); Eigen::VectorXd B = EigenFunctions::MVproduct(ReducedVectorsB, thetaonB); Eigen::VectorXd x = A.fullPivLu().solve(B); Eigen::VectorXd full = ModesTEig * x; t2 = std::chrono::high_resolution_clock::now(); time_span = std::chrono::duration_cast> (t2 - t1); time_rom += time_span.count(); // Export volScalarField Tred("Tred", T); Tred = Foam2Eigen::Eigen2field(Tred, full); ITHACAstream::exportSolution(Tred, name(i + 1), "./ITHACAoutput/" + Folder); Tonline.append((Tred).clone()); } } }; int main(int argc, char* argv[]) { // Construct the case DEIMLaplacian example(argc, argv); // Read some parameters from file ITHACAparameters* para = ITHACAparameters::getInstance(example._mesh(), example._runTime()); // Create the offline parameters for the solve example.mu = ITHACAutilities::rand(100, 2, -0.5, 0.5); // Solve the offline problem to compute the snapshots for the projections example.OfflineSolve(example.mu, "Offline"); // Compute the POD modes ITHACAPOD::getModes(example.Tfield, example.Tmodes, example._T().name(), example.podex, 0, 0, 20); // Compute the offline part of the DEIM procedure example.PODDEIM(); // Construct a new set of parameters Eigen::MatrixXd par_new1 = ITHACAutilities::rand(100, 2, -0.5, 0.5); // Solve the online problem with the new parameters example.OnlineSolve(par_new1, "Online_red"); // Solve a new full problem with the new parameters (necessary to compute speed up and error) DEIMLaplacian example_new(argc, argv); example_new.OnlineSolveFull(par_new1, "Online_full"); // Output some infos Info << endl << "The FOM Solve took: " << example_new.time_full << " seconds." << endl; Info << endl << "The ROM Solve took: " << example.time_rom << " seconds." << endl; Info << endl << "The Speed-up is: " << example_new.time_full / example.time_rom << endl << endl; Eigen::MatrixXd error = ITHACAutilities::errorL2Abs(example_new.Tfield, example.Tonline); Info << "The mean L2 error is: " << error.mean() << endl; return 0; }