#include <config.h> #include <array> #include <vector> #include <fstream> #include <iostream> #include <dune/common/indices.hh> #include <dune/common/bitsetvector.hh> #include <dune/common/parametertree.hh> #include <dune/common/parametertreeparser.hh> #include <dune/common/float_cmp.hh> #include <dune/common/math.hh> #include <dune/geometry/quadraturerules.hh> #include <dune/grid/uggrid.hh> #include <dune/grid/yaspgrid.hh> #include <dune/grid/io/file/vtk/subsamplingvtkwriter.hh> #include <dune/istl/matrix.hh> #include <dune/istl/bcrsmatrix.hh> #include <dune/istl/multitypeblockmatrix.hh> #include <dune/istl/multitypeblockvector.hh> #include <dune/istl/matrixindexset.hh> #include <dune/istl/solvers.hh> #include <dune/istl/spqr.hh> #include <dune/istl/preconditioners.hh> #include <dune/istl/io.hh> #include <dune/functions/functionspacebases/interpolate.hh> #include <dune/functions/backends/istlvectorbackend.hh> #include <dune/functions/functionspacebases/powerbasis.hh> #include <dune/functions/functionspacebases/compositebasis.hh> #include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/functions/functionspacebases/periodicbasis.hh> #include <dune/functions/functionspacebases/subspacebasis.hh> #include <dune/functions/functionspacebases/boundarydofs.hh> #include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh> #include <dune/functions/gridfunctions/gridviewfunction.hh> #include <dune/common/fvector.hh> #include <dune/common/fmatrix.hh> #include <dune/microstructure/matrix_operations.hh> #include <dune/microstructure/CorrectorComputer.hh> #include <dune/microstructure/EffectiveQuantitiesComputer.hh> #include <dune/microstructure/prestrainedMaterial.hh> #include <dune/solvers/solvers/umfpacksolver.hh> #include <dune/istl/eigenvalue/test/matrixinfo.hh> #include <dune/fufem/dunepython.hh> #include <any> #include <variant> #include <string> #include <iomanip> #include <filesystem> using namespace Dune; using namespace MatrixOperations; /** * @brief In the special case of a parametrized laminate (Lemma 4.5) in * [Böhnlein,Neukamm,Padilla-Garza,Sander - A homogenized bending theory for prestrained plates] * some of the effective quantities can be computed analytically. * This test compares the analytical quantities with numerical results. */ ////////////////////////////////////////////////// // Infrastructure for handling periodicity ////////////////////////////////////////////////// // Check whether two points are equal on R/Z x R/Z x R auto equivalent = [](const FieldVector<double,3>& x, const FieldVector<double,3>& y) { return ( (FloatCmp::eq(x[0],y[0]) or FloatCmp::eq(x[0]+1,y[0]) or FloatCmp::eq(x[0]-1,y[0])) and (FloatCmp::eq(x[1],y[1]) or FloatCmp::eq(x[1]+1,y[1]) or FloatCmp::eq(x[1]-1,y[1])) and (FloatCmp::eq(x[2],y[2])) ); }; int main(int argc, char *argv[]) { MPIHelper::instance(argc, argv); Dune::Timer globalTimer; //--- setup Log-File std::fstream log; std::cout << "Current path is " << std::filesystem::current_path() << '\n'; std::filesystem::path file_path = (__FILE__); std::cout<< "File path: " << file_path<<std::endl; std::cout << "dir_path: " << file_path.parent_path() << std::endl; std::string dir_path = file_path.parent_path(); // ParameterTree parameterSet; // if (argc < 2) // ParameterTreeParser::readINITree(dir_path + "/parametrizedlaminate.parset", parameterSet); // else // { // ParameterTreeParser::readINITree(argv[1], parameterSet); // ParameterTreeParser::readOptions(argc, argv, parameterSet); // } // ParameterTree parameterSet; // if (argc < 2) // ParameterTreeParser::readINITree("parset/parametrizedlaminate.parset", parameterSet); // else // { // ParameterTreeParser::readINITree(argv[1], parameterSet); // ParameterTreeParser::readOptions(argc, argv, parameterSet); // } // ParameterTree parameterSet; // if (argc < 2) // ParameterTreeParser::readINITree("/parset/parametrizedlaminate.parset", parameterSet); // else // { // ParameterTreeParser::readINITree(argv[1], parameterSet); // ParameterTreeParser::readOptions(argc, argv, parameterSet); // } //--- Start Python interpreter // Python::start(); // Python::Reference main = Python::import("__main__"); // Python::run("import math"); // Python::runStream() // << std::endl << "import sys" // << std::endl << "sys.path.append('" << dir_path << "')" // << std::endl; // Start Python interpreter Python::start(); auto pyMain = Python::main(); pyMain.runStream() << std::endl << "import math" << std::endl << "import sys" << std::endl << "sys.path.append('" << dir_path << "')" << std::endl; auto pyModule = pyMain.import("parametrized_laminate"); ParameterTree parameterSet; pyModule.get("parameterSet").toC(parameterSet); // read possible further parameters from the command line ParameterTreeParser::readOptions(argc, argv, parameterSet); // Print all parameters, to make them appear in the log file std::cout << "Input parameters:" << std::endl; parameterSet.report(); constexpr int dim = 3; constexpr int dimWorld = 3; /////////////////////////////////// // Generate the grid /////////////////////////////////// // --- Corrector Problem Domain (-1/2,1/2)^3: FieldVector<double,dim> lower({-1.0/2.0, -1.0/2.0, -1.0/2.0}); FieldVector<double,dim> upper({1.0/2.0, 1.0/2.0, 1.0/2.0}); int gridLevel = 3; std::array<int, dim> nElements = {(int)std::pow(2,gridLevel) ,(int)std::pow(2,gridLevel) ,(int)std::pow(2,gridLevel)}; std::cout << "Number of Grid-Elements in each direction: " << nElements << std::endl; using CellGridType = YaspGrid<dim, EquidistantOffsetCoordinates<double, dim> >; CellGridType grid_CE(lower,upper,nElements); using GridView = CellGridType::LeafGridView; const GridView gridView_CE = grid_CE.leafGridView(); //--- Choose a finite element space for Cell Problem using namespace Functions::BasisFactory; Functions::BasisFactory::Experimental::PeriodicIndexSet periodicIndices; //--- get PeriodicIndices for periodicBasis (Don't do the following in real life: It has quadratic run-time in the number of vertices.) for (const auto& v1 : vertices(gridView_CE)) for (const auto& v2 : vertices(gridView_CE)) if (equivalent(v1.geometry().corner(0), v2.geometry().corner(0))) { periodicIndices.unifyIndexPair({gridView_CE.indexSet().index(v1)}, {gridView_CE.indexSet().index(v2)}); } //--- setup first order periodic Lagrange-Basis auto Basis_CE = makeBasis( gridView_CE, power<dim>( Functions::BasisFactory::Experimental::periodic(lagrange<1>(), periodicIndices), flatLexicographic() )); /////////////////////////////////// // Create prestrained material object /////////////////////////////////// auto material = prestrainedMaterial(gridView_CE,parameterSet,pyModule); // --- Get scale ratio double gamma = parameterSet.get<double>("gamma",1.0); //------------------------------------------------------------------------------------------------ //--- Compute Correctors auto correctorComputer = CorrectorComputer(Basis_CE, material, gamma, log, parameterSet); correctorComputer.assemble(); correctorComputer.solve(); //--- Compute effective quantities auto effectiveQuantitiesComputer = EffectiveQuantitiesComputer(correctorComputer,material); effectiveQuantitiesComputer.computeEffectiveQuantities(); //--- get effective quantities auto Qeff = effectiveQuantitiesComputer.getQeff(); auto Beff = effectiveQuantitiesComputer.getBeff(); printmatrix(std::cout, Qeff, "Matrix Qeff", "--"); printvector(std::cout, Beff, "Beff", "--"); /** * @brief Compute analytical effective quantitites * */ //Parameters double theta = 0.25; double mu_1 = 1.0; double theta_mu = 2.0; double mu_2 = theta_mu * mu_1; double rho_1 = 1.0; double theta_rho = 2.0; double rho_2 = rho_1*theta_rho; //Effective quantities double q_1 = mu_1 * (theta_mu / (6*(theta + (1 - theta)*theta_mu))); double q_2 = (mu_1/6.0) * ((1-theta) + theta*theta_mu); double Beff_1 = (3.0*rho_1/2.0) * (1-(theta*(1+theta_rho))); double Beff_2 = (3.0*rho_1/2.0) * ((1-theta*(1+theta_mu*theta_rho))/(1-theta+theta*theta_mu)); double Beff_3 = 0.0; // std::cout << "q_1: " << q_1 << std::endl; // std::cout << "q_2: " << q_2 << std::endl; // std::cout << "Beff_1: " << Beff_1 << std::endl; // std::cout << "Beff_2: " << Beff_2 << std::endl; // std::cout << "Beff_3: " << Beff_3 << std::endl; /** * @brief Compare numerical and analytical results. * */ if( std::abs(q_1 - Qeff[0][0]) > 1e-2) { std::cout << "std::abs(q_1 - Qeff[0][0]):" << std::abs(q_1 - Qeff[0][0]) << std::endl; std::cerr << std::setprecision(9); std::cerr << "Computed Qeff[0][0] is " << Qeff[0][0] << " but " << q_1 << " was expected!" << std::endl; return 1; } if( std::abs(q_2 - Qeff[1][1]) > 1e-2) { std::cerr << std::setprecision(9); std::cerr << "Computed Qeff[1][1] is " << Qeff[1][1] << " but " << q_2 << " was expected!" << std::endl; return 1; } if( std::abs(Beff_1 - Beff[0]) > 1e-2) { std::cerr << std::setprecision(9); std::cerr << "Computed Beff[0] is " << Beff[0] << " but " << Beff_1 << " was expected!" << std::endl; return 1; } if( std::abs(Beff_2 - Beff[1]) > 1e-2) { std::cerr << std::setprecision(9); std::cerr << "Computed Beff[1] is " << Beff[1] << " but " << Beff_2 << " was expected!" << std::endl; return 1; } if( std::abs(Beff_3 - Beff[2]) > 1e-2) { std::cerr << std::setprecision(9); std::cerr << "Computed Beff[2] is " << Beff[2] << " but " << Beff_3 << " was expected!" << std::endl; return 1; } if( (Qeff[2][2] < Qeff[0][0]) || (Qeff[2][2] > Qeff[1][1]) ) { std::cerr << std::setprecision(9); std::cerr << "Computed Qeff[2][2] is " << Qeff[2][2] << " does not lie between Qeff[0][0]:" << Qeff[0][0] << " and Qeff[1][1]:" << Qeff[1][1] << " as was expected!" << std::endl; return 1; } std::cout << "Total time elapsed: " << globalTimer.elapsed() << std::endl; std::cout << "Test parametrizedlaminatetest passed." << std::endl; return 0; }