From 016d5c367d07f69c7ca141ef358b1e08b9ef871b Mon Sep 17 00:00:00 2001 From: Klaus <klaus.boehnlein@tu-dresden.de> Date: Thu, 9 Sep 2021 18:52:21 +0200 Subject: [PATCH] Add Stripped-down version of Cell-Problem for the computation of mu_gamma (significant speed-up) --- src/CMakeLists.txt | 1 + src/Cell-Problem_muGamma.cc | 1142 +++++++++++++++++++++++++++++++++++ 2 files changed, 1143 insertions(+) create mode 100644 src/Cell-Problem_muGamma.cc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 402c96f0..73e5b2f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ set(programs Cell-Problem + Cell-Problem_muGamma ) diff --git a/src/Cell-Problem_muGamma.cc b/src/Cell-Problem_muGamma.cc new file mode 100644 index 00000000..5c620bdd --- /dev/null +++ b/src/Cell-Problem_muGamma.cc @@ -0,0 +1,1142 @@ +#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/prestrain_material_geometry.hh> +#include <dune/microstructure/matrix_operations.hh> +#include <dune/microstructure/vtk_filler.hh> //TEST + + +#include <dune/functions/functionspacebases/hierarchicvectorwrapper.hh> + +// #include <dune/fufem/discretizationerror.hh> +// #include <boost/multiprecision/cpp_dec_float.hpp> +// #include <boost/any.hpp> + +#include <any> +#include <variant> +#include <string> +#include <iomanip> + +using namespace Dune; +using namespace MatrixOperations; + +// ------------------------------------------------------------------------ +// +// This is a stripped-down Version of Cell-Problem.cc +// that only computes mu_gamma = q_3 in a faster manner +// i.e. only the third corrector phi_3 is needed. +// ------------------------------------------------------------------------ + + + + + + + + + + + + + +////////////////////////////////////////////////////////////////////// +// Helper functions for Table-Output +////////////////////////////////////////////////////////////////////// +/*! Center-aligns string within a field of width w. Pads with blank spaces + to enforce alignment. */ +std::string center(const std::string s, const int w) { + std::stringstream ss, spaces; + int padding = w - s.size(); // count excess room to pad + for(int i=0; i<padding/2; ++i) + spaces << " "; + ss << spaces.str() << s << spaces.str(); // format with padding + if(padding>0 && padding%2!=0) // if odd #, add 1 space + ss << " "; + return ss.str(); +} + +/* Convert double to string with specified number of places after the decimal + and left padding. */ +template<class type> +std::string prd(const type x, const int decDigits, const int width) { + std::stringstream ss; +// ss << std::fixed << std::right; + ss << std::scientific << std::right; // Use scientific Output! + ss.fill(' '); // fill space around displayed # + ss.width(width); // set width around displayed # + ss.precision(decDigits); // set # places after decimal + ss << x; + return ss.str(); +} + + + + + +template<class Basis> +auto arbitraryComponentwiseIndices(const Basis& basis, + const int elementNumber, + const int leafIdx + ) +{ + // (Local Approach -- works for non Lagrangian-Basis too) + // Input : elementNumber & localIdx + // Output : determine all Component-Indices that correspond to that basis-function + auto localView = basis.localView(); + + FieldVector<int,3> row; + int elementCounter = 0; + + for (const auto& element : elements(basis.gridView())) + { + if(elementCounter == elementNumber) // get arbitraryIndex(global) for each Component ..alternativ:gridView.indexSet + { + localView.bind(element); + + for (int k = 0; k < 3; k++) + { + auto rowLocal = localView.tree().child(k).localIndex(leafIdx); //Input: LeafIndex! TODO bräuchte hier (Inverse ) Local-to-Leaf Idx Map + row[k] = localView.index(rowLocal); + // std::cout << "rowLocal:" << rowLocal << std::endl; + // std::cout << "row[k]:" << row[k] << std::endl; + } + } + elementCounter++; + } + return row; +} + + + + +template<class LocalView, class Matrix, class localFunction1, class localFunction2> +void computeElementStiffnessMatrix(const LocalView& localView, + Matrix& elementMatrix, + const localFunction1& mu, + const localFunction2& lambda, + const double gamma + ) +{ + // Local StiffnessMatrix of the form: + // | phi*phi m*phi | + // | phi *m m*m | + using Element = typename LocalView::Element; + const Element element = localView.element(); + auto geometry = element.geometry(); + constexpr int dim = Element::dimension; + constexpr int dimWorld = dim; + using MatrixRT = FieldMatrix< double, dimWorld, dimWorld>; + + elementMatrix.setSize(localView.size()+3, localView.size()+3); //extend by dim ´R_sym^{2x2} + elementMatrix = 0; + + // LocalBasis-Offset + const int localPhiOffset = localView.size(); + + const auto& localFiniteElement = localView.tree().child(0).finiteElement(); + const auto nSf = localFiniteElement.localBasis().size(); +// std::cout << "localView.size(): " << localView.size() << std::endl; +// std::cout << "nSf : " << nSf << std::endl; + + /////////////////////////////////////////////// + // Basis for R_sym^{2x2} // wird nicht als Funktion benötigt da konstant... + ////////////////////////////////////////////// + MatrixRT G_1 {{1.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0, 0.0}}; + MatrixRT G_2 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0, 0.0, 0.0}}; + MatrixRT G_3 {{0.0, 1.0/sqrt(2), 0.0}, {1.0/sqrt(2), 0.0, 0.0}, {0.0, 0.0, 0.0}}; + std::array<MatrixRT,3 > basisContainer = {G_1, G_2, G_3}; + +// int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1)+5; // TEST + int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1); + const auto& quad = QuadratureRules<double,dim>::rule(element.type(), orderQR); + + for (const auto& quadPoint : quad) + { + const auto& quadPos = quadPoint.position(); + const auto jacobianInverseTransposed = geometry.jacobianInverseTransposed(quadPos); + const auto integrationElement = geometry.integrationElement(quadPos); + + std::vector< FieldMatrix< double, 1, dim> > referenceGradients; + localFiniteElement.localBasis().evaluateJacobian(quadPos, + referenceGradients); + // Compute the shape function gradients on the grid element + std::vector<FieldVector<double,dim> > gradients(referenceGradients.size()); + + for (size_t i=0; i<gradients.size(); i++) + jacobianInverseTransposed.mv(referenceGradients[i][0], gradients[i]); + + for (size_t k=0; k < dimWorld; k++) + for (size_t i=0; i < nSf; i++) + { + // "phi*phi"-part + for (size_t l=0; l< dimWorld; l++) + for (size_t j=0; j < nSf; j++ ) + { + // (scaled) Deformation gradient of the ansatz basis function + MatrixRT defGradientU(0); + defGradientU[k][0] = gradients[i][0]; // Y + defGradientU[k][1] = gradients[i][1]; //X2 + defGradientU[k][2] = (1.0/gamma)*gradients[i][2]; //X3 + // printmatrix(std::cout, defGradientU , "defGradientU", "--"); + // (scaled) Deformation gradient of the test basis function + MatrixRT defGradientV(0); + defGradientV[l][0] = gradients[j][0]; // Y + defGradientV[l][1] = gradients[j][1]; //X2 + defGradientV[l][2] = (1.0/gamma)*gradients[j][2]; //X3 + + double energyDensity = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), defGradientU, defGradientV); +// double energyDensity = generalizedDensity(mu(quadPos), lambda(quadPos), defGradientU, defGradientV); // also works.. + + size_t col = localView.tree().child(k).localIndex(i); + size_t row = localView.tree().child(l).localIndex(j); + elementMatrix[row][col] += energyDensity * quadPoint.weight() * integrationElement; + + // "m*phi" & "phi*m" - part + for( size_t m=0; m<3; m++) + { + double energyDensityGphi = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), basisContainer[m], defGradientV); + + auto value = energyDensityGphi * quadPoint.weight() * integrationElement; + elementMatrix[row][localPhiOffset+m] += value; + elementMatrix[localPhiOffset+m][row] += value; + } + } + } + // "m*m"-part + for(size_t m=0; m<3; m++) + for(size_t n=0; n<3; n++) + { + double energyDensityGG = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), basisContainer[m], basisContainer[n]); + elementMatrix[localPhiOffset+m][localPhiOffset+n]= energyDensityGG * quadPoint.weight() * integrationElement; + } + } +} + + + +// Get the occupation pattern of the stiffness matrix +template<class Basis, class ParameterSet> +void getOccupationPattern(const Basis& basis, MatrixIndexSet& nb, ParameterSet& parameterSet) +{ + // OccupationPattern: + // | phi*phi m*phi | + // | phi *m m*m | + + auto localView = basis.localView(); + const int phiOffset = basis.dimension(); + + nb.resize(basis.size()+3, basis.size()+3); + + for (const auto& element : elements(basis.gridView())) + { + localView.bind(element); + for (size_t i=0; i<localView.size(); i++) + { + // The global index of the i-th vertex of the element + auto row = localView.index(i); + for (size_t j=0; j<localView.size(); j++ ) + { + // The global index of the j-th vertex of the element + auto col = localView.index(j); + nb.add(row[0],col[0]); // nun würde auch nb.add(row,col) gehen.. + } + } + for (size_t i=0; i<localView.size(); i++) + { + auto row = localView.index(i); + + for (size_t j=0; j<3; j++ ) + { + nb.add(row,phiOffset+j); // m*phi part of StiffnessMatrix + nb.add(phiOffset+j,row); // phi*m part of StiffnessMatrix + } + } + for (size_t i=0; i<3; i++ ) + for (size_t j=0; j<3; j++ ) + { + nb.add(phiOffset+i,phiOffset+j); // m*m part of StiffnessMatrix + } + } + ////////////////////////////////////////////////////////////////// + // setOneBaseFunctionToZero + ////////////////////////////////////////////////////////////////// + if(parameterSet.template get<bool>("set_oneBasisFunction_Zero ", true)){ + FieldVector<int,3> row; + unsigned int arbitraryLeafIndex = parameterSet.template get<unsigned int>("arbitraryLeafIndex", 0); + unsigned int arbitraryElementNumber = parameterSet.template get<unsigned int>("arbitraryElementNumber", 0); + + const auto& localFiniteElement = localView.tree().child(0).finiteElement(); // macht keinen Unterschied ob hier k oder 0.. + const auto nSf = localFiniteElement.localBasis().size(); + assert(arbitraryLeafIndex < nSf ); + assert(arbitraryElementNumber < basis.gridView().size(0)); // "arbitraryElementNumber larger than total Number of Elements" + + //Determine 3 global indices (one for each component of an arbitrary local FE-function) + row = arbitraryComponentwiseIndices(basis,arbitraryElementNumber,arbitraryLeafIndex); + + for (int k = 0; k<3; k++) + nb.add(row[k],row[k]); + } +} + + + +// Compute the source term for a single element +// < L (sym[D_gamma*nabla phi_i] + M_i ), x_3G_alpha > +template<class LocalView, class LocalFunction1, class LocalFunction2, class Vector, class Force> +void computeElementLoadVector( const LocalView& localView, + LocalFunction1& mu, + LocalFunction2& lambda, + const double gamma, + Vector& elementRhs, + const Force& forceTerm + ) +{ + // | f*phi| + // | --- | + // | f*m | + using Element = typename LocalView::Element; + const auto element = localView.element(); + const auto geometry = element.geometry(); + constexpr int dim = Element::dimension; + constexpr int dimWorld = dim; + + using MatrixRT = FieldMatrix< double, dimWorld, dimWorld>; + + // Set of shape functions for a single element + const auto& localFiniteElement= localView.tree().child(0).finiteElement(); + const auto nSf = localFiniteElement.localBasis().size(); + + elementRhs.resize(localView.size() +3); + elementRhs = 0; + + // LocalBasis-Offset + const int localPhiOffset = localView.size(); + + /////////////////////////////////////////////// + // Basis for R_sym^{2x2} + ////////////////////////////////////////////// + MatrixRT G_1 {{1.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0, 0.0}}; + MatrixRT G_2 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0, 0.0, 0.0}}; + MatrixRT G_3 {{0.0, 1.0/sqrt(2), 0.0}, {1.0/sqrt(2), 0.0, 0.0}, {0.0, 0.0, 0.0}}; + std::array<MatrixRT,3 > basisContainer = {G_1, G_2, G_3}; + +// int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1)+5; // TEST + int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1); // für simplex + const auto& quad = QuadratureRules<double,dim>::rule(element.type(), orderQR); + + for (const auto& quadPoint : quad) + { + const FieldVector<double,dim>& quadPos = quadPoint.position(); + const auto jacobian = geometry.jacobianInverseTransposed(quadPos); + const double integrationElement = geometry.integrationElement(quadPos); + + std::vector<FieldMatrix<double,1,dim> > referenceGradients; + + localFiniteElement.localBasis().evaluateJacobian(quadPos, referenceGradients); + + std::vector< FieldVector< double, dim> > gradients(referenceGradients.size()); + for (size_t i=0; i< gradients.size(); i++) + jacobian.mv(referenceGradients[i][0], gradients[i]); + + // "f*phi"-part + for (size_t i=0; i < nSf; i++) + for (size_t k=0; k < dimWorld; k++) + { + // Deformation gradient of the ansatz basis function + MatrixRT defGradientV(0); + defGradientV[k][0] = gradients[i][0]; // Y + defGradientV[k][1] = gradients[i][1]; // X2 + defGradientV[k][2] = (1.0/gamma)*gradients[i][2]; // X3 + + double energyDensity = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), defGradientV, forceTerm(quadPos)); + size_t row = localView.tree().child(k).localIndex(i); + elementRhs[row] += energyDensity * quadPoint.weight() * integrationElement; + } + + // "f*m"-part + for (size_t m=0; m<3; m++) + { + double energyDensityfG = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), basisContainer[m], forceTerm(quadPos)); + elementRhs[localPhiOffset+m] += energyDensityfG * quadPoint.weight() * integrationElement; + } + } +} + + + +template<class Basis, class Matrix, class LocalFunction1, class LocalFunction2, class ParameterSet> +void assembleCellStiffness(const Basis& basis, + LocalFunction1& muLocal, + LocalFunction2& lambdaLocal, + const double gamma, + Matrix& matrix, + ParameterSet& parameterSet + ) +{ + std::cout << "assemble Stiffness-Matrix begins." << std::endl; + + MatrixIndexSet occupationPattern; + getOccupationPattern(basis, occupationPattern, parameterSet); + occupationPattern.exportIdx(matrix); + matrix = 0; + + auto localView = basis.localView(); + const int phiOffset = basis.dimension(); + + for (const auto& element : elements(basis.gridView())) + { + localView.bind(element); + muLocal.bind(element); + lambdaLocal.bind(element); + const int localPhiOffset = localView.size(); + + //std::cout << "localPhiOffset : " << localPhiOffset << std::endl; + Dune::Matrix<FieldMatrix<double,1,1> > elementMatrix; + computeElementStiffnessMatrix(localView, elementMatrix, muLocal, lambdaLocal, gamma); + //printmatrix(std::cout, elementMatrix, "ElementMatrix", "--"); + //std::cout << "elementMatrix.N() : " << elementMatrix.N() << std::endl; + //std::cout << "elementMatrix.M() : " << elementMatrix.M() << std::endl; + + ////////////////////////////////////////////////////////////////////////////// + // GLOBAL STIFFNES ASSEMBLY + ////////////////////////////////////////////////////////////////////////////// + for (size_t i=0; i<localPhiOffset; i++) + for (size_t j=0; j<localPhiOffset; j++ ) + { + auto row = localView.index(i); + auto col = localView.index(j); + matrix[row][col] += elementMatrix[i][j]; + } + for (size_t i=0; i<localPhiOffset; i++) + for(size_t m=0; m<3; m++) + { + auto row = localView.index(i); + matrix[row][phiOffset+m] += elementMatrix[i][localPhiOffset+m]; + matrix[phiOffset+m][row] += elementMatrix[localPhiOffset+m][i]; + } + for (size_t m=0; m<3; m++ ) + for (size_t n=0; n<3; n++ ) + matrix[phiOffset+m][phiOffset+n] += elementMatrix[localPhiOffset+m][localPhiOffset+n]; + + // printmatrix(std::cout, matrix, "StiffnessMatrix", "--"); + } +} + + +template<class Basis, class LocalFunction1, class LocalFunction2, class Vector, class Force> +void assembleCellLoad(const Basis& basis, + LocalFunction1& muLocal, + LocalFunction2& lambdaLocal, + const double gamma, + Vector& b, + const Force& forceTerm + ) +{ + // std::cout << "assemble load vector." << std::endl; + b.resize(basis.size()+3); + b = 0; + + auto localView = basis.localView(); + const int phiOffset = basis.dimension(); + + // Transform G_alpha's to GridViewFunctions/LocalFunctions + auto loadGVF = Dune::Functions::makeGridViewFunction(forceTerm, basis.gridView()); + auto loadFunctional = localFunction(loadGVF); + + for (const auto& element : elements(basis.gridView())) + { + localView.bind(element); + muLocal.bind(element); + lambdaLocal.bind(element); + loadFunctional.bind(element); + + const int localPhiOffset = localView.size(); + // std::cout << "localPhiOffset : " << localPhiOffset << std::endl; + + BlockVector<FieldVector<double,1> > elementRhs; + computeElementLoadVector(localView, muLocal, lambdaLocal, gamma, elementRhs, loadFunctional); +// printvector(std::cout, elementRhs, "elementRhs", "--"); +// printvector(std::cout, elementRhs, "elementRhs", "--"); + ////////////////////////////////////////////////////////////////////////////// + // GLOBAL LOAD ASSEMBLY + ////////////////////////////////////////////////////////////////////////////// + for (size_t p=0; p<localPhiOffset; p++) + { + auto row = localView.index(p); + b[row] += elementRhs[p]; + } + for (size_t m=0; m<3; m++ ) + b[phiOffset+m] += elementRhs[localPhiOffset+m]; + //printvector(std::cout, b, "b", "--"); + } +} + + + +template<class Basis, class LocalFunction1, class LocalFunction2, class MatrixFunction> +auto energy(const Basis& basis, + LocalFunction1& mu, + LocalFunction2& lambda, + const MatrixFunction& matrixFieldFuncA, + const MatrixFunction& matrixFieldFuncB) +{ + +// TEST HIGHER PRECISION +// using float_50 = boost::multiprecision::cpp_dec_float_50; +// float_50 higherPrecEnergy = 0.0; + double energy = 0.0; + constexpr int dim = Basis::LocalView::Element::dimension; + constexpr int dimWorld = dim; + + auto localView = basis.localView(); + + auto matrixFieldAGVF = Dune::Functions::makeGridViewFunction(matrixFieldFuncA, basis.gridView()); + auto matrixFieldA = localFunction(matrixFieldAGVF); + auto matrixFieldBGVF = Dune::Functions::makeGridViewFunction(matrixFieldFuncB, basis.gridView()); + auto matrixFieldB = localFunction(matrixFieldBGVF); + + using GridView = typename Basis::GridView; + using Domain = typename GridView::template Codim<0>::Geometry::GlobalCoordinate; + using MatrixRT = FieldMatrix< double, dimWorld, dimWorld>; +// TEST +// FieldVector<double,3> testvector = {1.0 , 1.0 , 1.0}; +// printmatrix(std::cout, matrixFieldFuncB(testvector) , "matrixFieldB(testvector) ", "--"); + + for (const auto& e : elements(basis.gridView())) + { + localView.bind(e); + matrixFieldA.bind(e); + matrixFieldB.bind(e); + mu.bind(e); + lambda.bind(e); + + double elementEnergy = 0.0; + //double elementEnergy_HP = 0.0; + + auto geometry = e.geometry(); + const auto& localFiniteElement = localView.tree().child(0).finiteElement(); + + //int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1 + 5 ); // TEST + int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1); + const QuadratureRule<double, dim>& quad = QuadratureRules<double, dim>::rule(e.type(), orderQR); + + for (const auto& quadPoint : quad) + { + const auto& quadPos = quadPoint.position(); + const double integrationElement = geometry.integrationElement(quadPos); + + auto strain1 = matrixFieldA(quadPos); + auto strain2 = matrixFieldB(quadPos); + + double energyDensity = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), strain1, strain2); + + elementEnergy += energyDensity * quadPoint.weight() * integrationElement; + //elementEnergy_HP += energyDensity * quadPoint.weight() * integrationElement; + } + energy += elementEnergy; + //higherPrecEnergy += elementEnergy_HP; + } +// TEST +// std::cout << std::setprecision(std::numeric_limits<float_50>::digits10) << higherPrecEnergy << std::endl; + return energy; +} + + + +template<class Basis, class Matrix, class Vector, class ParameterSet> // changed to take only one load... +void setOneBaseFunctionToZero(const Basis& basis, + Matrix& stiffnessMatrix, + Vector& load_alpha, + ParameterSet& parameterSet + ) +{ + std::cout << "Setting one Basis-function to zero" << std::endl; + + constexpr int dim = Basis::LocalView::Element::dimension; + + unsigned int arbitraryLeafIndex = parameterSet.template get<unsigned int>("arbitraryLeafIndex", 0); + unsigned int arbitraryElementNumber = parameterSet.template get<unsigned int>("arbitraryElementNumber", 0); + //Determine 3 global indices (one for each component of an arbitrary local FE-function) + FieldVector<int,3> row = arbitraryComponentwiseIndices(basis,arbitraryElementNumber,arbitraryLeafIndex); + + for (int k = 0; k < dim; k++) + { + load_alpha[row[k]] = 0.0; + auto cIt = stiffnessMatrix[row[k]].begin(); + auto cEndIt = stiffnessMatrix[row[k]].end(); + for (; cIt!=cEndIt; ++cIt) + *cIt = (cIt.index()==row[k]) ? 1.0 : 0.0; + } +} + + + +template<class Basis> +auto childToIndexMap(const Basis& basis, + const int k + ) +{ + // Input : child/component + // Output : determine all Indices that belong to that component + auto localView = basis.localView(); + + std::vector<int> r = { }; + // for (int n: r) + // std::cout << n << ","<< std::endl; + + // Determine global indizes for each component k = 1,2,3.. in order to subtract correct (component of) integral Mean + // (global) Indices that correspond to component k = 1,2,3 + for(const auto& element : elements(basis.gridView())) + { + localView.bind(element); + const auto& localFiniteElement = localView.tree().child(k).finiteElement(); + const auto nSf = localFiniteElement.localBasis().size(); + + for(size_t j=0; j<nSf; j++) + { + auto Localidx = localView.tree().child(k).localIndex(j); // local indices + r.push_back(localView.index(Localidx)); // global indices + } + } + // Delete duplicate elements + // first remove consecutive (adjacent) duplicates + auto last = std::unique(r.begin(), r.end()); + r.erase(last, r.end()); + // sort followed by unique, to remove all duplicates + std::sort(r.begin(), r.end()); + last = std::unique(r.begin(), r.end()); + r.erase(last, r.end()); + + return r; +} + + +template<class Basis, class Vector> +auto integralMean(const Basis& basis, + Vector& coeffVector + ) +{ + // computes integral mean of given LocalFunction + + constexpr int dim = Basis::LocalView::Element::dimension; + + auto GVFunction = Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dim>>(basis,coeffVector); + auto localfun = localFunction(GVFunction); + + auto localView = basis.localView(); + + FieldVector<double,3> r = {0.0, 0.0, 0.0}; + double area = 0.0; + + // Compute Area integral & integral of FE-function + for(const auto& element : elements(basis.gridView())) + { + localView.bind(element); + localfun.bind(element); + const auto& localFiniteElement = localView.tree().child(0).finiteElement(); + + int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1); + const QuadratureRule<double, dim>& quad = QuadratureRules<double, dim>::rule(element.type(), orderQR); + + for(const auto& quadPoint : quad) + { + const auto& quadPos = quadPoint.position(); + const double integrationElement = element.geometry().integrationElement(quadPos); + area += quadPoint.weight() * integrationElement; + + r += localfun(quadPos) * quadPoint.weight() * integrationElement; + } + } + // std::cout << "Domain-Area: " << area << std::endl; + return (1.0/area) * r ; +} + + +template<class Basis, class Vector> +auto subtractIntegralMean(const Basis& basis, + Vector& coeffVector + ) +{ + // Substract correct Integral mean from each associated component function + auto IM = integralMean(basis, coeffVector); + + constexpr int dim = Basis::LocalView::Element::dimension; + + for(size_t k=0; k<dim; k++) + { + //std::cout << "Integral-Mean: " << IM[k] << std::endl; + auto idx = childToIndexMap(basis,k); + + for ( int i : idx) + coeffVector[i] -= IM[k]; + } +} + + + +////////////////////////////////////////////////// +// 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); + + ParameterTree parameterSet; + if (argc < 2) + ParameterTreeParser::readINITree("../../inputs/cellsolver.parset", parameterSet); + else + { + ParameterTreeParser::readINITree(argv[1], parameterSet); + ParameterTreeParser::readOptions(argc, argv, parameterSet); + } + + // Output setter +// std::string outputPath = parameterSet.get("outputPath", "../../outputs/output.txt"); +// std::string outputPath = parameterSet.get("outputPath", "/home/klaus/Desktop/DUNE/dune-microstructure/outputs/output.txt"); + std::string outputPath = parameterSet.get("outputPath", "/home/klaus/Desktop/DUNE/dune-microstructure/outputs"); +// std::string MatlabPath = parameterSet.get("MatlabPath", "/home/klaus/Desktop/DUNE/dune-microstructure/Matlab-Programs"); +// std::string outputPath = "/home/klaus/Desktop/DUNE/dune-microstructure/outputs/output.txt"; + std::fstream log; + log.open(outputPath + "/output.txt" ,std::ios::out); + + std::cout << "outputPath:" << outputPath << std::endl; + +// parameterSet.report(log); // short Alternativ + + constexpr int dim = 3; + constexpr int dimWorld = 3; + + /////////////////////////////////// + // Get Parameters/Data + /////////////////////////////////// + double gamma = parameterSet.get<double>("gamma",3.0); // ratio dimension reduction to homogenization + double alpha = parameterSet.get<double>("alpha", 2.0); + double theta = parameterSet.get<double>("theta",1.0/4.0); + /////////////////////////////////// + // Get Material Parameters + /////////////////////////////////// + std::string imp = parameterSet.get<std::string>("material_prestrain_imp", "analytical_Example"); + double beta = parameterSet.get<double>("beta",2.0); + double mu1 = parameterSet.get<double>("mu1",10.0);; + double mu2 = beta*mu1; + double lambda1 = parameterSet.get<double>("lambda1",0.0);; + double lambda2 = beta*lambda1; + + // Plate geometry settings + double width = parameterSet.get<double>("width", 1.0); //geometry cell, cross section + // double len = parameterSet.get<double>("len", 10.0); //length + // double height = parameterSet.get<double>("h", 0.1); //rod thickness + // double eps = parameterSet.get<double>("eps", 0.1); //size of perioticity cell + + /////////////////////////////////// + // Get Prestrain/Parameters + /////////////////////////////////// +// unsigned int prestraintype = parameterSet.get<unsigned int>("prestrainType", "analytical_Example"); //OLD +// std::string prestraintype = parameterSet.get<std::string>("prestrainType", "analytical_Example"); +// double rho1 = parameterSet.get<double>("rho1", 1.0); +// double rho2 = alpha*rho1; +// auto prestrainImp = PrestrainImp(rho1, rho2, theta, width); +// auto B_Term = prestrainImp.getPrestrain(prestraintype); + + + + log << "----- Input Parameters -----: " << std::endl; +// log << "prestrain imp: " << prestraintype << "\nrho1 = " << rho1 << "\nrho2 = " << rho2 << std::endl; + log << "alpha: " << alpha << std::endl; + log << "gamma: " << gamma << std::endl; + log << "theta: " << theta << std::endl; + log << "beta: " << beta << std::endl; + log << "material parameters: " << std::endl; + log << "mu1: " << mu1 << "\nmu2: " << mu2 << std::endl; + log << "lambda1: " << lambda1 <<"\nlambda2: " << lambda2 << std::endl; + log << "----------------------------: " << std::endl; + + /////////////////////////////////// + // Generate the grid + /////////////////////////////////// + + //Corrector Problem Domain: + unsigned int cellDomain = parameterSet.get<unsigned int>("cellDomain", 1); + // (shifted) 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}); + if (cellDomain == 2) + { + // Domain : [0,1)^2 x (-1/2, 1/2) + FieldVector<double,dim> lower({0.0, 0.0, -1.0/2.0}); + FieldVector<double,dim> upper({1.0, 1.0, 1.0/2.0}); + } + + std::array<int,2> numLevels = parameterSet.get<std::array<int,2>>("numLevels", {1,3}); + + int levelCounter = 0; + + /////////////////////////////////// + // Create Data Storage + /////////////////////////////////// + // Storage:: #1 level #2 L2SymError #3 L2SymErrorOrder #4 L2Norm(sym) #5 L2Norm(sym-analytic) #6 L2Norm(phi_1) + std::vector<std::variant<std::string, size_t , double>> Storage_Error; + + // Storage:: #1 level #2 |q1_a-q1_c| #3 |q2_a-q2_c| #4 |q3_a-q3_c| #5 |b1_a-b1_c| #6 |b2_a-b2_c| #7 |b3_a-b3_c| + std::vector<std::variant<std::string, size_t , double>> Storage_Quantities; + + +// for(const size_t &level : numLevels) // explixite Angabe der levels.. {2,4} + for(size_t level = numLevels[0] ; level <= numLevels[1]; level++) // levels von bis.. [2,4] + { + std::cout << " ----------------------------------" << std::endl; + std::cout << "Level: " << level << std::endl; + std::cout << " ----------------------------------" << std::endl; + + Storage_Error.push_back(level); + Storage_Quantities.push_back(level); + std::array<int, dim> nElements = { (int)std::pow(2,level) , (int)std::pow(2,level) , (int)std::pow(2,level) }; + + std::cout << "Number of Elements in each direction: " << nElements << std::endl; + log << "Number of 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(); + + using MatrixRT = FieldMatrix< double, dimWorld, dimWorld>; + using Domain = GridView::Codim<0>::Geometry::GlobalCoordinate; + using Func2Tensor = std::function< MatrixRT(const Domain&) >; + using VectorCT = BlockVector<FieldVector<double,1> >; + using MatrixCT = BCRSMatrix<FieldMatrix<double,1,1> >; + + /////////////////////////////////// + // Create Lambda-Functions for material Parameters depending on microstructure + /////////////////////////////////// + + auto materialImp = IsotropicMaterialImp(); + auto muTerm = materialImp.getMu(parameterSet); + auto lambdaTerm = materialImp.getLambda(parameterSet); + + auto muGridF = Dune::Functions::makeGridViewFunction(muTerm, gridView_CE); + auto muLocal = localFunction(muGridF); + auto lambdaGridF = Dune::Functions::makeGridViewFunction(lambdaTerm, gridView_CE); + auto lambdaLocal = localFunction(lambdaGridF); + + /////////////////////////////////// + // --- Choose Solver --- + // 1 : CG-Solver + // 2 : GMRES + // 3 : QR + /////////////////////////////////// + unsigned int Solvertype = parameterSet.get<unsigned int>("Solvertype", 1); + + // Print Options + bool print_debug = parameterSet.get<bool>("print_debug", false); + + + bool write_materialFunctions = parameterSet.get<bool>("write_materialFunctions", false); + bool write_prestrainFunctions = parameterSet.get<bool>("write_prestrainFunctions", false); + + + bool write_corrector_phi3 = parameterSet.get<bool>("write_corrector_phi3", false); + bool write_L2Error = parameterSet.get<bool>("write_L2Error", false); + bool write_IntegralMean = parameterSet.get<bool>("write_IntegralMean", false); + + ///////////////////////////////////////////////////////// + // Choose a finite element space for Cell Problem + ///////////////////////////////////////////////////////// + using namespace Functions::BasisFactory; + Functions::BasisFactory::Experimental::PeriodicIndexSet periodicIndices; + + // 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)}); + } + + // First order periodic Lagrange-Basis + auto Basis_CE = makeBasis( + gridView_CE, + power<dim>( + Functions::BasisFactory::Experimental::periodic(lagrange<1>(), periodicIndices), + flatLexicographic())); + + log << "size of FiniteElementBasis: " << Basis_CE.size() << std::endl; + const int phiOffset = Basis_CE.size(); + + ///////////////////////////////////////////////////////// + // Data structures: Stiffness matrix and right hand side vectors + ///////////////////////////////////////////////////////// + VectorCT load_alpha1, load_alpha2, load_alpha3; + MatrixCT stiffnessMatrix_CE; + + bool set_IntegralZero = parameterSet.get<bool>("set_IntegralZero", true); + bool set_oneBasisFunction_Zero = false; + bool substract_integralMean = false; + if(set_IntegralZero) + { + set_oneBasisFunction_Zero = true; + substract_integralMean = true; + } + + ///////////////////////////////////////////////////////// + // Define "rhs"-functions + ///////////////////////////////////////////////////////// + Func2Tensor x3G_3 = [] (const Domain& x) { + return MatrixRT{{0.0, 1.0/sqrt(2)*x[2], 0.0}, {1.0/sqrt(2)*x[2], 0.0, 0.0}, {0.0, 0.0, 0.0}}; + }; + + Func2Tensor x3G_3neg = [x3G_3] (const Domain& x) {return -1.0*x3G_3(x);}; + + + + /////////////////////////////////////////////// + // Basis for R_sym^{2x2} + ////////////////////////////////////////////// + MatrixRT G_1 {{1.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0, 0.0}}; + MatrixRT G_2 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0, 0.0, 0.0}}; + MatrixRT G_3 {{0.0, 1.0/sqrt(2), 0.0}, {1.0/sqrt(2), 0.0, 0.0}, {0.0, 0.0, 0.0}}; + std::array<MatrixRT,3 > basisContainer = {G_1, G_2, G_3}; + // printmatrix(std::cout, basisContainer[0] , "G_1", "--"); + // printmatrix(std::cout, basisContainer[1] , "G_2", "--"); + // printmatrix(std::cout, basisContainer[2] , "´G_3", "--"); + // log << basisContainer[0] << std::endl; + + + ////////////////////////////////////////////////////////////////////// + // Determine global indices of components for arbitrary (local) index + ////////////////////////////////////////////////////////////////////// + int arbitraryLeafIndex = parameterSet.get<unsigned int>("arbitraryLeafIndex", 0); // localIdx..assert Number < #ShapeFcts + int arbitraryElementNumber = parameterSet.get<unsigned int>("arbitraryElementNumber", 0); + + FieldVector<int,3> row; + row = arbitraryComponentwiseIndices(Basis_CE,arbitraryElementNumber,arbitraryLeafIndex); + if(print_debug) + printvector(std::cout, row, "row" , "--"); + + ///////////////////////////////////////////////////////// + // Assemble the system + ///////////////////////////////////////////////////////// + assembleCellStiffness(Basis_CE, muLocal, lambdaLocal, gamma, stiffnessMatrix_CE, parameterSet); + assembleCellLoad(Basis_CE, muLocal, lambdaLocal,gamma, load_alpha3 ,x3G_3neg); // only third corrector is needed + // printmatrix(std::cout, stiffnessMatrix_CE, "StiffnessMatrix", "--"); + // printvector(std::cout, load_alpha1, "load_alpha1", "--"); + + + + // set one basis-function to zero + if(set_oneBasisFunction_Zero) + { + setOneBaseFunctionToZero(Basis_CE, stiffnessMatrix_CE, load_alpha3, parameterSet); + } + + //////////////////////////////////////////////////// + // Compute solution + //////////////////////////////////////////////////// + VectorCT x_3 = load_alpha3; + + if (Solvertype == 1) // CG - SOLVER + { + std::cout << "------------ CG - Solver ------------" << std::endl; + MatrixAdapter<MatrixCT, VectorCT, VectorCT> op(stiffnessMatrix_CE); + + + + // Sequential incomplete LU decomposition as the preconditioner + SeqILU<MatrixCT, VectorCT, VectorCT> ilu0(stiffnessMatrix_CE,1.0); + int iter = parameterSet.get<double>("iterations_CG", 999); + // Preconditioned conjugate-gradient solver + CGSolver<VectorCT> solver(op, + ilu0, //NULL, + 1e-8, // desired residual reduction factorlack + iter, // maximum number of iterations + 2); // verbosity of the solver + InverseOperatorResult statistics; +// std::cout << "solve linear system for x_1.\n"; +// solver.apply(x_1, load_alpha1, statistics); +// std::cout << "solve linear system for x_2.\n"; +// solver.apply(x_2, load_alpha2, statistics); + std::cout << "solve linear system for x_3.\n"; + solver.apply(x_3, load_alpha3, statistics); + log << "Solver-type used: " <<" CG-Solver" << std::endl; + } + //////////////////////////////////////////////////////////////////////////////////// + + else if (Solvertype ==2) // GMRES - SOLVER + { + + std::cout << "------------ GMRES - Solver ------------" << std::endl; + // Turn the matrix into a linear operator + MatrixAdapter<MatrixCT,VectorCT,VectorCT> stiffnessOperator(stiffnessMatrix_CE); + + // Fancy (but only) way to not have a preconditioner at all + Richardson<VectorCT,VectorCT> preconditioner(1.0); + + // Construct the iterative solver + RestartedGMResSolver<VectorCT> solver( + stiffnessOperator, // Operator to invert + preconditioner, // Preconditioner + 1e-10, // Desired residual reduction factor + 500, // Number of iterations between restarts, + // here: no restarting + 500, // Maximum number of iterations + 2); // Verbosity of the solver + + // Object storing some statistics about the solving process + InverseOperatorResult statistics; + + + solver.apply(x_3, load_alpha3, statistics); + log << "Solver-type used: " <<" GMRES-Solver" << std::endl; + } + //////////////////////////////////////////////////////////////////////////////////// + else if ( Solvertype == 3)// QR - SOLVER + { + + std::cout << "------------ QR - Solver ------------" << std::endl; + log << "solveLinearSystems: We use QR solver.\n"; + //TODO install suitesparse + SPQR<MatrixCT> sPQR(stiffnessMatrix_CE); + sPQR.setVerbosity(1); + InverseOperatorResult statisticsQR; + + sPQR.apply(x_3, load_alpha3, statisticsQR); + log << "Solver-type used: " <<" QR-Solver" << std::endl; + } + + //////////////////////////////////////////////////////////////////////////////////// + // Extract phi_alpha & M_alpha coefficients + //////////////////////////////////////////////////////////////////////////////////// + VectorCT phi_3; + phi_3.resize(Basis_CE.size()); + phi_3 = 0; + + for(size_t i=0; i<Basis_CE.size(); i++) + { + + phi_3[i] = x_3[i]; + } + + FieldVector<double,3> m_1, m_2, m_3; + + for(size_t i=0; i<3; i++) + { + m_3[i] = x_3[phiOffset+i]; + } + // assemble M_alpha's (actually iota(M_alpha) ) + + MatrixRT M_1(0), M_2(0), M_3(0); + + for(size_t i=0; i<3; i++) + { + M_3 += m_3[i]*basisContainer[i]; + } + + std::cout << "--- plot corrector-Matrices M_alpha --- " << std::endl; +// printmatrix(std::cout, M_3, "Corrector-Matrix M_3", "--"); + log << "---------- OUTPUT ----------" << std::endl; + log << " --------------------" << std::endl; + log << "Corrector-Matrix M_3: \n" << M_3 << std::endl; + log << " --------------------" << std::endl; + + //////////////////////////////////////////////////////////////////////////// + // Substract Integral-mean + //////////////////////////////////////////////////////////////////////////// + using SolutionRange = FieldVector<double,dim>; + + if(substract_integralMean) + { + std::cout << " --- substracting integralMean --- " << std::endl; + subtractIntegralMean(Basis_CE, phi_3); + subtractIntegralMean(Basis_CE, x_3); + } + + //////////////////////////////////////////////////////////////////////////// + // Make a discrete function from the FE basis and the coefficient vector + //////////////////////////////////////////////////////////////////////////// // +// auto correctorFunction_3 = Functions::makeDiscreteGlobalBasisFunction<SolutionRange>( +// Basis_CE, +// phi_3); + + + ///////////////////////////////////////////////////////// + // Compute effective quantities: Elastic law & Prestrain + ///////////////////////////////////////////////////////// + VectorCT tmp1; + assembleCellLoad(Basis_CE, muLocal, lambdaLocal, gamma, tmp1 ,x3G_3); + double GGterm = 0.0; + GGterm = energy(Basis_CE, muLocal, lambdaLocal, x3G_3, x3G_3 ); + auto mu_gamma = (x_3*tmp1) + GGterm; + log << "mu_gamma=" << mu_gamma << std::endl; + + std::cout << "mu_gamma:" << mu_gamma << std::endl; + Storage_Quantities.push_back(mu_gamma); + + + levelCounter++; + } // Level-Loop End + + + log.close(); +} -- GitLab