/*---------------------------------------------------------------------------*\ ██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗ ██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║ ██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║ ██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝ ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝ * 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 a heat transfer Reduction Problem SourceFiles 02thermalBlock.C \*---------------------------------------------------------------------------*/ #include #include "fvCFD.H" #include "IOmanip.H" #include "Time.H" #include "laplacianProblem.H" #include "ReducedLaplacian.H" #include "ITHACAPOD.H" #include "ITHACAutilities.H" #include #define _USE_MATH_DEFINES #include /// \brief Class where the tutorial number 2 is implemented. /// \details It is a child of the laplacianProblem class and some of its /// functions are overridden to be adapted to the specific case. class tutorial02: public laplacianProblem { public: explicit tutorial02(int argc, char* argv[]) : laplacianProblem(argc, argv), T(_T()), nu(_nu()), S(_S()) {} //! [tutorial02] /// Temperature field volScalarField& T; /// Diffusivity field volScalarField& nu; /// Source term field volScalarField& S; /// It perform an offline Solve void offlineSolve(word folder = "./ITHACAoutput/Offline/") { if (offline) { ITHACAstream::read_fields(Tfield, "T", folder); mu_samples = ITHACAstream::readMatrix(folder + "/mu_samples_mat.txt"); } else { List mu_now(9); scalar IF = 0; for (label i = 0; i < mu.rows(); i++) { for (label j = 0; j < mu.cols() ; j++) { mu_now[j] = mu(i, j); theta[j] = mu(i, j); } assignIF(T, IF); Info << i << endl; truthSolve(mu_now, folder); } } } /// Define the source term function void SetSource() { volScalarField yPos = T.mesh().C().component(vector::Y).ref(); volScalarField xPos = T.mesh().C().component(vector::X).ref(); forAll(S, counter) { S[counter] = Foam::sin(xPos[counter] / 0.9 * M_PI) + Foam::sin( yPos[counter] / 0.9 * M_PI); } } /// Compute the diffusivity in each subdomain void compute_nu() { nu_list.resize(9); volScalarField nu1(nu); volScalarField nu2(nu); volScalarField nu3(nu); volScalarField nu4(nu); volScalarField nu5(nu); volScalarField nu6(nu); volScalarField nu7(nu); volScalarField nu8(nu); volScalarField nu9(nu); Eigen::MatrixXd Box1(2, 3); Box1 << 0, 0, 0, 0.3, 0.3, 0.1; Eigen::MatrixXd Box2(2, 3); Box2 << 0.3, 0, 0, 0.6, 0.3, 0.1; Eigen::MatrixXd Box3(2, 3); Box3 << 0.6, 0, 0, 0.91, 0.3, 0.1; Eigen::MatrixXd Box4(2, 3); Box4 << 0, 0.3, 0, 0.3, 0.6, 0.1; Eigen::MatrixXd Box5(2, 3); Box5 << 0.3, 0.3, 0, 0.6, 0.6, 0.1; Eigen::MatrixXd Box6(2, 3); Box6 << 0.6, 0.3, 0, 0.91, 0.6, 0.1; Eigen::MatrixXd Box7(2, 3); Box7 << 0, 0.6, 0, 0.3, 0.91, 0.1; Eigen::MatrixXd Box8(2, 3); Box8 << 0.3, 0.61, 0, 0.6, 0.91, 0.1; Eigen::MatrixXd Box9(2, 3); Box9 << 0.6, 0.6, 0, 0.9, 0.91, 0.1; ITHACAutilities::setBoxToValue(nu1, Box1, 1.0); ITHACAutilities::setBoxToValue(nu2, Box2, 1.0); ITHACAutilities::setBoxToValue(nu3, Box3, 1.0); ITHACAutilities::setBoxToValue(nu4, Box4, 1.0); ITHACAutilities::setBoxToValue(nu5, Box5, 1.0); ITHACAutilities::setBoxToValue(nu6, Box6, 1.0); ITHACAutilities::setBoxToValue(nu7, Box7, 1.0); ITHACAutilities::setBoxToValue(nu8, Box8, 1.0); ITHACAutilities::setBoxToValue(nu9, Box9, 1.0); nu_list.set(0, (nu1).clone()); nu_list.set(1, (nu2).clone()); nu_list.set(2, (nu3).clone()); nu_list.set(3, (nu4).clone()); nu_list.set(4, (nu5).clone()); nu_list.set(5, (nu6).clone()); nu_list.set(6, (nu7).clone()); nu_list.set(7, (nu8).clone()); nu_list.set(8, (nu9).clone()); } /// Construct the operator_list where each term of the affine decomposition is stored void assemble_operator() { for (int i = 0; i < nu_list.size(); i++) { operator_list.append(fvm::laplacian(nu_list[i], T)); } } }; void offline_stage(tutorial02& example, tutorial02& FOM_test); void online_stage(tutorial02& example, tutorial02& FOM_test); int main(int argc, char* argv[]) { #if OPENFOAM > 1812 // load stage to perform argList::addOption("stage", "offline", "Perform offline stage"); argList::addOption("stage", "online", "Perform online stage"); // add options for parallel run HashTable validParOptions; validParOptions.set ( "stage", "offline" ); validParOptions.set ( "stage", "online" ); Pstream::addValidParOptions(validParOptions); // Construct the tutorial object tutorial02 example(argc, argv); /// Create a new instance of the FOM problem for testing purposes tutorial02 FOM_test(argc, argv); if (example._args().get("stage").match("offline")) { // perform the offline stage, extracting the modes from the snapshots' // dataset corresponding to parOffline offline_stage(example, FOM_test); } else if (example._args().get("stage").match("online")) { // load precomputed modes and reduced matrices offline_stage(example, FOM_test); // perform online solve with respect to the parameters in parOnline online_stage(example, FOM_test); } else { Info << "Pass '-stage offline', '-stage online'" << endl; } #else if (argc == 1) { Info << "Pass 'offline' or 'online' as first arguments." << endl; return 0; } // process arguments removing "offline" or "online" keywords int argc_proc = argc - 1; char* argv_proc[argc_proc]; argv_proc[0] = argv[0]; if (argc > 2) { std::copy(argv + 2, argv + argc, argv_proc + 1); } argc--; // Construct the tutorial object tutorial02 example(argc, argv); /// Create a new instance of the FOM problem for testing purposes tutorial02 FOM_test(argc, argv); if (std::strcmp(argv[1], "offline") == 0) { // perform the offline stage, extracting the modes from the snapshots' // dataset corresponding to parOffline offline_stage(example, FOM_test); } else if (std::strcmp(argv[1], "online") == 0) { // load precomputed modes and reduced matrices offline_stage(example, FOM_test); // perform online solve with respect to the parameters in parOnline online_stage(example, FOM_test); } else { Info << "Pass offline, online" << endl; } #endif return 0; } void offline_stage(tutorial02& example, tutorial02& FOM_test) { // Read some parameters from file ITHACAparameters* para = ITHACAparameters::getInstance(example._mesh(), example._runTime()); int NmodesTout = para->ITHACAdict->lookupOrDefault("NmodesTout", 15); int NmodesTproj = para->ITHACAdict->lookupOrDefault("NmodesTproj", 10); // Set the number of parameters example.Pnumber = 9; example.Tnumber = 500; // Set the parameters example.setParameters(); // Set the parameter ranges, in all the subdomains the diffusivity varies between // 0.001 and 0.1 example.mu_range.col(0) = Eigen::MatrixXd::Ones(9, 1) * 0.001; example.mu_range.col(1) = Eigen::MatrixXd::Ones(9, 1) * 0.1; // Generate the Parameters example.genRandPar(500); // Set the size of the list of values that are multiplying the affine forms example.theta.resize(9); // Set the source term example.SetSource(); // Compute the diffusivity field for each subdomain example.compute_nu(); // Assemble all the operators of the affine decomposition example.assemble_operator(); // Perform an Offline Solve example.offlineSolve(); // Perform a POD decomposition and get the modes ITHACAPOD::getModes(example.Tfield, example.Tmodes, example._T().name(), example.podex, 0, 0, NmodesTout); // Perform the Galerkin projection onto the space spanned by the POD modes example.project(NmodesTproj); FOM_test.offline = false; FOM_test.Pnumber = 9; FOM_test.Tnumber = 50; // Set the parameters FOM_test.setParameters(); // Set the parameter ranges, in all the subdomains the diffusivity varies between // 0.001 and 0.1 FOM_test.mu_range.col(0) = Eigen::MatrixXd::Ones(9, 1) * 0.001; FOM_test.mu_range.col(1) = Eigen::MatrixXd::Ones(9, 1) * 0.1; // Generate the Parameters FOM_test.genRandPar(50); // Set the size of the list of values that are multiplying the affine forms FOM_test.theta.resize(9); // Set the source term FOM_test.SetSource(); // Compute the diffusivity field for each subdomain FOM_test.compute_nu(); // Assemble all the operators of the affine decomposition FOM_test.assemble_operator(); // Perform an Offline Solve FOM_test.offlineSolve("./ITHACAoutput/FOMtest"); } void online_stage(tutorial02& example, tutorial02& FOM_test) { // Create a reduced object reducedLaplacian reduced(example); // Solve the online reduced problem some new values of the parameters for (int i = 0; i < FOM_test.mu.rows(); i++) { reduced.solveOnline(FOM_test.mu.row(i)); } // Reconstruct the solution and store it into Reconstruction folder reduced.reconstruct("./ITHACAoutput/Reconstruction"); // Compute the error on the testing set Eigen::MatrixXd error = ITHACAutilities::errorL2Rel(FOM_test.Tfield, reduced.Trec); }