diff --git a/dune/microstructure/CorrectorComputer.hh b/dune/microstructure/CorrectorComputer.hh index 576d2afa7963054ec90a7909ad951735c3fb4033..1fbb2ede0009cb59b1d6f229c4e5626ff6834da8 100644 --- a/dune/microstructure/CorrectorComputer.hh +++ b/dune/microstructure/CorrectorComputer.hh @@ -1,6 +1,8 @@ #ifndef DUNE_MICROSTRUCTURE_CORRECTORCOMPUTER_HH #define DUNE_MICROSTRUCTURE_CORRECTORCOMPUTER_HH +#include <map> + #include <dune/common/parametertree.hh> // #include <dune/common/float_cmp.hh> #include <dune/istl/matrixindexset.hh> @@ -12,6 +14,8 @@ #include <dune/istl/eigenvalue/test/matrixinfo.hh> // TEST: compute condition Number #include <dune/solvers/solvers/umfpacksolver.hh> +#include <dune/microstructure/voigthelper.hh> + using namespace MatrixOperations; using std::shared_ptr; @@ -45,12 +49,13 @@ protected: const Material& material_; + double gamma_; + fstream& log_; // Output-log const Dune::ParameterTree& parameterSet_; // const FuncScalar mu_; // const FuncScalar lambda_; - double gamma_; MatrixCT stiffnessMatrix_; VectorCT load_alpha1_,load_alpha2_,load_alpha3_; //right-hand side(load) vectors @@ -59,15 +64,14 @@ protected: VectorCT phi_1_, phi_2_, phi_3_; // Corrector phi_i coefficient vectors Dune::FieldVector<double,3> m_1_, m_2_, m_3_; // Corrector m_i coefficient vectors - MatrixRT M1_, M2_, M3_; // (assembled) corrector matrices M_i - const std::array<MatrixRT*, 3 > mContainer = {&M1_ , &M2_, &M3_}; + // (assembled) corrector matrices M_i + std::array<MatrixRT, 3 > mContainer; const std::array<VectorCT, 3> phiContainer = {phi_1_,phi_2_,phi_3_}; // ---- Basis for R_sym^{2x2} - MatrixRT G1_ {{1.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0, 0.0}}; - MatrixRT G2_ {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0, 0.0, 0.0}}; - MatrixRT G3_ {{0.0, 1.0/sqrt(2.0), 0.0}, {1.0/sqrt(2.0), 0.0, 0.0}, {0.0, 0.0, 0.0}}; - std::array<MatrixRT,3 > MatrixBasisContainer_ = {G1_, G2_, G3_}; + // Could really be constexpr static, but then we would need to write the basis here directly in Voigt notation. + // However, I suspect that our Voigt representation may still change in the future. + const std::array<VoigtVector<double,3>,3 > matrixBasis_; Func2Tensor x3G_1_ = [] (const Domain& x) { return MatrixRT{{1.0*x[2], 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; //TODO könnte hier sign übergeben? @@ -100,6 +104,9 @@ public: gamma_(gamma), log_(log), parameterSet_(parameterSet), + matrixBasis_(std::array<VoigtVector<double,3>,3>{matrixToVoigt(Dune::FieldMatrix<double,3,3>({{1, 0, 0}, {0, 0, 0}, {0, 0, 0}})), + matrixToVoigt(Dune::FieldMatrix<double,3,3>({{0, 0, 0}, {0, 1, 0}, {0, 0, 0}})), + matrixToVoigt(Dune::FieldMatrix<double,3,3>({{0, 1/std::sqrt(2.0), 0}, {1/std::sqrt(2.0), 0, 0}, {0, 0, 0}}))}), phiOffset_(basis.size()) { @@ -153,7 +160,7 @@ public: // shared_ptr<std::array<VectorRT, 3>> getBasiscontainer(){return make_shared<std::array<VectorRT, 3>>(basisContainer_);} - auto getMatrixBasiscontainer(){return make_shared<std::array<MatrixRT,3 >>(MatrixBasisContainer_);} + auto getMatrixBasiscontainer(){return make_shared<std::array<VoigtVector<double,3>,3 >>(matrixBasis_);} // auto getx3MatrixBasiscontainer(){return make_shared<std::array<Func2Tensor, 3>>(x3MatrixBasisContainer_);} auto getx3MatrixBasiscontainer(){return x3MatrixBasisContainer_;} @@ -218,7 +225,7 @@ public: 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" + assert(arbitraryElementNumber < (std::size_t)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(arbitraryElementNumber,arbitraryLeafIndex); @@ -236,7 +243,14 @@ public: // const localFunction2& lambda // ) + /** \brief Compute the stiffness matrix for one element + * + * \param quadRule The quadrature rule to be used + * \param phaseAtQuadPoint The material phase (i.e., the type of material) at each quadrature point + */ void computeElementStiffnessMatrix(const typename Basis::LocalView& localView, + const Dune::QuadratureRule<double,dim>& quadRule, + const std::vector<int>& phaseAtQuadPoint, ElementMatrixCT& elementMatrix ) { @@ -252,14 +266,6 @@ public: // auto elasticityTensor = material_.getElasticityTensor(); - // auto indicatorFunction = material_.getIndicatorFunction(); - auto localIndicatorFunction = material_.getLocalIndicatorFunction(); - localIndicatorFunction.bind(element); - // auto indicatorFunctionGVF = material_.getIndicatorFunctionGVF(); - // auto indicatorFunction = localFunction(indicatorFunctionGVF); - // indicatorFunction.bind(element); - // Func2int indicatorFunction = *material_.getIndicatorFunction(); - // LocalBasis-Offset const int localPhiOffset = localView.size(); @@ -269,28 +275,8 @@ public: // 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.0}}; - MatrixRT G_2 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 0.0}}; - MatrixRT G_3 {{0.0, 1.0/sqrt(2.0), 0.0}, {1.0/sqrt(2.0), 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); - // int orderQR = 0; - // int orderQR = 1; - // int orderQR = 2; - // int orderQR = 3; - const auto& quad = Dune::QuadratureRules<double,dim>::rule(element.type(), orderQR); - - // double elementContribution = 0.0; - - // std::cout << "Print QuadratureOrder:" << orderQR << std::endl; //TEST` - int QPcounter= 0; - for (const auto& quadPoint : quad) + for (const auto& quadPoint : quadRule) { QPcounter++; const auto& quadPos = quadPoint.position(); @@ -304,7 +290,7 @@ public: jacobians[i] = jacobians[i] * geometryJacobianInverse; // Compute the scaled deformation gradient for each shape function - std::vector<std::array<MatrixRT,dimworld> > deformationGradient(nSf); + std::vector<std::array<VoigtVector<double,dim>,dimworld> > deformationGradient(nSf); for (size_t i=0; i < nSf; i++) { @@ -313,12 +299,12 @@ public: MatrixRT defGradientV(0); defGradientV[k] = jacobians[i][0]; - deformationGradient[i][k] = sym(crossSectionDirectionScaling((1.0/gamma_),defGradientV)); + deformationGradient[i][k] = symVoigt(crossSectionDirectionScaling((1.0/gamma_),defGradientV)); } } // Compute the material phase that the current quadrature point is in - const auto phase = localIndicatorFunction(quadPos); + const auto phase = phaseAtQuadPoint[QPcounter-1]; for (size_t l=0; l< dimworld; l++) for (size_t j=0; j < nSf; j++ ) @@ -371,7 +357,7 @@ public: // printmatrix(std::cout, material_.ElasticityTensor(defGradientU,localIndicatorFunction(quadPos)), "material_.ElasticityTensor(defGradientU,localIndicatorFunction(quadPos)", "--"); - double energyDensity= scalarProduct(material_.applyElasticityTensor(deformationGradient[i][k],phase),deformationGradient[j][l]); + double energyDensity= voigtScalarProduct(material_.applyElasticityTensor(deformationGradient[i][k],phase),deformationGradient[j][l]); // double energyDensity= scalarProduct(material_.ElasticityTensor(defGradientU,localIndicatorFunction(quadPos)),sym(defGradientV)); // double energyDensity= scalarProduct(elasticityTensor(defGradientU,localIndicatorFunction(quadPos)),sym(defGradientV)); // double energyDensity= scalarProduct(elasticityTensor(defGradientU,indicatorFunction(element.geometry().global(quadPos))),sym(defGradientV)); @@ -412,7 +398,7 @@ public: - double energyDensityGphi = scalarProduct(material_.applyElasticityTensor(basisContainer[m],phase),deformationGradient[j][l]); + double energyDensityGphi = voigtScalarProduct(material_.applyElasticityTensor(matrixBasis_[m],phase),deformationGradient[j][l]); // double energyDensityGphi = scalarProduct(material_.ElasticityTensor(basisContainer[m],localIndicatorFunction(quadPos)),sym(defGradientV)); // double energyDensityGphi= scalarProduct(elasticityTensor(basisContainer[m],localIndicatorFunction(quadPos)),sym(defGradientV)); // std::cout << "scalarProduct(elasticityTensor(basisContainer[m],indicatorFunction(element.geometry().global(quadPos))),sym(defGradientV))" << scalarProduct(elasticityTensor(basisContainer[m],indicatorFunction(element.geometry().global(quadPos))),sym(defGradientV)) <<std::endl; @@ -461,7 +447,7 @@ public: - double energyDensityGG = scalarProduct(material_.applyElasticityTensor(basisContainer[m],phase),basisContainer[n]); + double energyDensityGG = voigtScalarProduct(material_.applyElasticityTensor(matrixBasis_[m],phase),matrixBasis_[n]); // double energyDensityGG = scalarProduct(material_.ElasticityTensor(basisContainer[m],localIndicatorFunction(quadPos)),sym(basisContainer[n])); // double energyDensityGG= scalarProduct(elasticityTensor(basisContainer[m],localIndicatorFunction(quadPos)),sym(basisContainer[n])); // double energyDensityGG= scalarProduct(elasticityTensor(basisContainer[m],indicatorFunction(element.geometry().global(quadPos))),sym(basisContainer[n])); @@ -535,14 +521,6 @@ public: // 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.0}}; - MatrixRT G_2 {{0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 0.0}}; - MatrixRT G_3 {{0.0, 1.0/sqrt(2.0), 0.0}, {1.0/sqrt(2.0), 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 = 0; // int orderQR = 1; @@ -586,19 +564,19 @@ public: for (size_t k=0; k < dimworld; k++) { // Deformation gradient of the ansatz basis function - MatrixRT defGradientV(0); - defGradientV[k][0] = jacobians[i][0][0]; // Y - defGradientV[k][1] = jacobians[i][0][1]; // X2 - // defGradientV[k][2] = (1.0/gamma_)*jacobians[i][0][2]; // - defGradientV[k][2] = jacobians[i][0][2]; // X3 + MatrixRT tmpDefGradientV(0); + tmpDefGradientV[k][0] = jacobians[i][0][0]; // Y + tmpDefGradientV[k][1] = jacobians[i][0][1]; // X2 + // tmpDefGradientV[k][2] = (1.0/gamma_)*jacobians[i][0][2]; // + tmpDefGradientV[k][2] = jacobians[i][0][2]; // X3 - defGradientV = sym(crossSectionDirectionScaling((1.0/gamma_),defGradientV)); + VoigtVector<double,3> defGradientV = symVoigt(crossSectionDirectionScaling((1.0/gamma_),tmpDefGradientV)); // double energyDensity= scalarProduct(material_.ElasticityTensorGlobal((-1.0)*forceTerm(quadPos),element.geometry().global(quadPos)),sym(defGradientV)); - double energyDensity= scalarProduct(material_.applyElasticityTensor((-1.0)*forceTerm(quadPos),localIndicatorFunction(quadPos)),sym(defGradientV)); + double energyDensity= voigtScalarProduct(material_.applyElasticityTensor((-1.0)*matrixToVoigt(forceTerm(quadPos)),localIndicatorFunction(quadPos)),defGradientV); // double energyDensity= scalarProduct(material_.ElasticityTensor((-1.0)*forceTerm(quadPos),localIndicatorFunction(quadPos)),sym(defGradientV)); // double energyDensity= scalarProduct(elasticityTensor((-1.0)*forceTerm(quadPos),localIndicatorFunction(quadPos)),sym(defGradientV)); // double energyDensity= scalarProduct(elasticityTensor((-1.0)*forceTerm(quadPos),indicatorFunction(element.geometry().global(quadPos))),sym(defGradientV)); @@ -624,7 +602,7 @@ public: // double energyDensityfG= scalarProduct(material_.ElasticityTensorGlobal((-1.0)*forceTerm(quadPos),element.geometry().global(quadPos)),sym(basisContainer[m])); - double energyDensityfG= scalarProduct(material_.applyElasticityTensor((-1.0)*forceTerm(quadPos),localIndicatorFunction(quadPos)),sym(basisContainer[m])); + double energyDensityfG= voigtScalarProduct(material_.applyElasticityTensor((-1.0)*matrixToVoigt(forceTerm(quadPos)),localIndicatorFunction(quadPos)),matrixBasis_[m]); // double energyDensityfG= scalarProduct(material_.ElasticityTensor((-1.0)*forceTerm(quadPos),localIndicatorFunction(quadPos)),sym(basisContainer[m])); // double energyDensityfG= scalarProduct(elasticityTensor((-1.0)*forceTerm(quadPos),localIndicatorFunction(quadPos)),sym(basisContainer[m])); // double energyDensityfG= scalarProduct(elasticityTensor((-1.0)*forceTerm(quadPos),indicatorFunction(element.geometry().global(quadPos))),sym(basisContainer[m])); @@ -657,6 +635,10 @@ public: auto localView = basis_.localView(); const int phiOffset = basis_.dimension(); + // A cache for the element stiffness matrices, if desired + bool cacheElementMatrices = true; + std::map<std::vector<int>, ElementMatrixCT> elementMatrixCache; + // auto muGridF = makeGridViewFunction(mu_, basis_.gridView()); // auto muLocal = localFunction(muGridF); // auto lambdaGridF = makeGridViewFunction(lambda_, basis_.gridView()); @@ -667,12 +649,51 @@ public: localView.bind(element); // muLocal.bind(element); // lambdaLocal.bind(element); - const int localPhiOffset = localView.size(); + const auto localPhiOffset = localView.size(); // Dune::Timer Time; //std::cout << "localPhiOffset : " << localPhiOffset << std::endl; + + // Determine a suitable quadrature rule + const auto& localFiniteElement = localView.tree().child(0).finiteElement(); + int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1); + const auto& quadRule = Dune::QuadratureRules<double,dim>::rule(element.type(), orderQR); + + // Determine the material phase at each quadrature point + auto localIndicatorFunction = material_.getLocalIndicatorFunction(); + localIndicatorFunction.bind(element); + + std::vector<int> phaseAtQuadPoint(quadRule.size()); + + for (std::size_t i=0; i<quadRule.size(); ++i) + phaseAtQuadPoint[i] = localIndicatorFunction(quadRule[i].position()); + ElementMatrixCT elementMatrix; - // computeElementStiffnessMatrix(localView, elementMatrix, muLocal, lambdaLocal); - computeElementStiffnessMatrix(localView, elementMatrix); + + // We know that all elements of the grid have the same geometry. Therefore, the element stiffness matrices + // depend only on the material phases at the quadrature points. In practice, a few particular phase distributions + // dominate (identical phase at all quadrature points). This makes caching the element matrices worthwhile. + // + // In principle the cache implemented here can get arbitrarily large. If that ever becomes a problem + // we need to implement a smarter cache. + if (cacheElementMatrices) + { + auto cachedMatrix = elementMatrixCache.find(phaseAtQuadPoint); + if (cachedMatrix != elementMatrixCache.end()) + { + // This copies the matrix. A smarter implementation would avoid this. + elementMatrix = (*cachedMatrix).second; + } + else + { + computeElementStiffnessMatrix(localView, quadRule, phaseAtQuadPoint, elementMatrix); + // This copies the matrix again. + elementMatrixCache.insert({phaseAtQuadPoint, elementMatrix}); + } + } + else // No caching + { + computeElementStiffnessMatrix(localView, quadRule, phaseAtQuadPoint, elementMatrix); + } // std::cout << "local assembly time:" << Time.elapsed() << std::endl; @@ -747,7 +768,7 @@ public: // lambdaLocal.bind(element); loadFunctional.bind(element); - const int localPhiOffset = localView.size(); + const auto localPhiOffset = localView.size(); // std::cout << "localPhiOffset : " << localPhiOffset << std::endl; VectorCT elementRhs; @@ -814,7 +835,7 @@ public: 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) - Dune::FieldVector<int,3> row = arbitraryComponentwiseIndices(arbitraryElementNumber,arbitraryLeafIndex); + Dune::FieldVector<std::size_t,3> row = arbitraryComponentwiseIndices(arbitraryElementNumber,arbitraryLeafIndex); for (int k = 0; k<dim; k++) { @@ -902,7 +923,7 @@ public: auto subtractIntegralMean(VectorCT& coeffVector) { - // Substract correct Integral mean from each associated component function + // Subtract correct integral mean from each associated component function auto IM = integralMean(coeffVector); for(size_t k=0; k<dim; k++) @@ -1100,30 +1121,27 @@ public: } // assemble M_alpha's (actually iota(M_alpha) ) - // MatrixRT M_1(0), M_2(0), M_3(0); - - M1_ = 0; - M2_ = 0; - M3_ = 0; + for (auto& matrix : mContainer) + matrix = 0; for(size_t i=0; i<3; i++) { - M1_ += m_1_[i]*MatrixBasisContainer_[i]; - M2_ += m_2_[i]*MatrixBasisContainer_[i]; - M3_ += m_3_[i]*MatrixBasisContainer_[i]; + mContainer[0] += m_1_[i]*voigtToMatrix(matrixBasis_[i]); + mContainer[1] += m_2_[i]*voigtToMatrix(matrixBasis_[i]); + mContainer[2] += m_3_[i]*voigtToMatrix(matrixBasis_[i]); } std::cout << "--- plot corrector-Matrices M_alpha --- " << std::endl; - printmatrix(std::cout, M1_, "Corrector-Matrix M_1", "--"); - printmatrix(std::cout, M2_, "Corrector-Matrix M_2", "--"); - printmatrix(std::cout, M3_, "Corrector-Matrix M_3", "--"); + printmatrix(std::cout, mContainer[0], "Corrector-Matrix M_1", "--"); + printmatrix(std::cout, mContainer[1], "Corrector-Matrix M_2", "--"); + printmatrix(std::cout, mContainer[2], "Corrector-Matrix M_3", "--"); log_ << "---------- OUTPUT ----------" << std::endl; log_ << " --------------------" << std::endl; - log_ << "Corrector-Matrix M_1: \n" << M1_ << std::endl; + log_ << "Corrector-Matrix M_1: \n" << mContainer[0] << std::endl; log_ << " --------------------" << std::endl; - log_ << "Corrector-Matrix M_2: \n" << M2_ << std::endl; + log_ << "Corrector-Matrix M_2: \n" << mContainer[1] << std::endl; log_ << " --------------------" << std::endl; - log_ << "Corrector-Matrix M_3: \n" << M3_ << std::endl; + log_ << "Corrector-Matrix M_3: \n" << mContainer[2] << std::endl; log_ << " --------------------" << std::endl; @@ -1138,7 +1156,7 @@ public: } if(substract_integralMean) { - std::cout << " --- substracting integralMean --- " << std::endl; + std::cout << " --- subtracting integralMean --- " << std::endl; subtractIntegralMean(phi_1_); subtractIntegralMean(phi_2_); subtractIntegralMean(phi_3_); @@ -1210,9 +1228,9 @@ public: computeL2Norm(); computeL2SymGrad(); - std::cout<< "Frobenius-Norm of M1_: " << M1_.frobenius_norm() << std::endl; - std::cout<< "Frobenius-Norm of M2_: " << M2_.frobenius_norm() << std::endl; - std::cout<< "Frobenius-Norm of M3_: " << M3_.frobenius_norm() << std::endl; + std::cout<< "Frobenius-Norm of M1_: " << mContainer[0].frobenius_norm() << std::endl; + std::cout<< "Frobenius-Norm of M2_: " << mContainer[1].frobenius_norm() << std::endl; + std::cout<< "Frobenius-Norm of M3_: " << mContainer[2].frobenius_norm() << std::endl; } void computeL2Norm() @@ -1281,7 +1299,6 @@ public: auto geometry = element.geometry(); const auto& localFiniteElement = localView.tree().child(0).finiteElement(); - const auto nSf = localFiniteElement.localBasis().size(); int orderQR = 2*(dim*localFiniteElement.localBasis().order()-1 ); const auto& quad = Dune::QuadratureRules<double,dim>::rule(element.type(), orderQR); @@ -1386,21 +1403,17 @@ public: const double integrationElement = geometry.integrationElement(quadPos); - auto Chi = sym(crossSectionDirectionScaling(1.0/gamma_, DerPhi2(quadPos))) + *mContainer[b]; + auto Chi = sym(crossSectionDirectionScaling(1.0/gamma_, DerPhi2(quadPos))) + mContainer[b]; - auto strain1 = DerPhi1(quadPos); - - - strain1 = crossSectionDirectionScaling(1.0/gamma_, strain1); - strain1 = sym(strain1); + const auto strain1 = symVoigt(crossSectionDirectionScaling(1.0/gamma_, DerPhi1(quadPos))); auto G = matrixFieldG(quadPos); // auto G = matrixFieldG(e.geometry().global(quadPos)); //TEST - auto tmp = G + *mContainer[a] + strain1; + auto tmp = matrixToVoigt(G + mContainer[a]) + strain1; - double energyDensity= scalarProduct(material_.applyElasticityTensor(tmp,localIndicatorFunction(quadPos)),sym(Chi)); + double energyDensity= voigtScalarProduct(material_.applyElasticityTensor(tmp,localIndicatorFunction(quadPos)),symVoigt(Chi)); // double energyDensity= scalarProduct(material_.ElasticityTensor(tmp,localIndicatorFunction(quadPos)),sym(Chi)); // double energyDensity = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), tmp, Chi); @@ -1423,7 +1436,7 @@ public: - // --- Check wheter stiffness matrix is symmetric + // --- Check whether stiffness matrix is symmetric void checkSymmetry() { std::cout << " Check Symmetry of stiffness matrix..." << std::endl; @@ -1433,7 +1446,7 @@ public: for (const auto& element : elements(basis_.gridView())) { localView.bind(element); - const int localPhiOffset = localView.size(); + const auto localPhiOffset = localView.size(); for(size_t i=0; i<localPhiOffset; i++) for(size_t j=0; j<localPhiOffset; j++ ) diff --git a/dune/microstructure/EffectiveQuantitiesComputer.hh b/dune/microstructure/EffectiveQuantitiesComputer.hh index e7deec3720486f76f10fd09032ef1dbb5c538656..c6e358d4c796396fba5d84d5371d5a975eda3457 100644 --- a/dune/microstructure/EffectiveQuantitiesComputer.hh +++ b/dune/microstructure/EffectiveQuantitiesComputer.hh @@ -162,7 +162,7 @@ public: const auto& quadPos = quadPoint.position(); const double integrationElement = geometry.integrationElement(quadPos); - auto Chi1 = sym(crossSectionDirectionScaling(1.0/gamma, localfun_a(quadPos))) + *MContainer[a]; + auto Chi1 = sym(crossSectionDirectionScaling(1.0/gamma, localfun_a(quadPos))) + MContainer[a]; auto G1 = matrixFieldG1(quadPos); @@ -170,10 +170,10 @@ public: // auto G1 = matrixFieldG1(e.geometry().global(quadPos)); //TEST // auto G2 = matrixFieldG2(e.geometry().global(quadPos)); //TEST - auto X1 = G1 + Chi1; + auto X1 = matrixToVoigt(G1 + Chi1); // auto X2 = G2 + Chi2; - double energyDensity= scalarProduct(material_.applyElasticityTensor(X1,localIndicatorFunction(quadPos)),sym(G2)); + double energyDensity= voigtScalarProduct(material_.applyElasticityTensor(X1,localIndicatorFunction(quadPos)), matrixToVoigt(sym(G2))); // double energyDensity= scalarProduct(material_.ElasticityTensor(X1,localIndicatorFunction(quadPos)),sym(G2)); // double energyDensity = linearizedStVenantKirchhoffDensity(mu(quadPos), lambda(quadPos), X1, G2); elementEnergy += energyDensity * quadPoint.weight() * integrationElement; // quad[quadPoint].weight() ??? @@ -188,7 +188,7 @@ public: // printmatrix(std::cout, prestrainPhaseValue_old, "prestrainPhaseValue_old", "--"); // printmatrix(std::cout, prestrainPhaseValue, "prestrainPhaseValue", "--"); // } - auto value = scalarProduct(material_.applyElasticityTensor(X1,localIndicatorFunction(quadPos)),sym(prestrainPhaseValue)); + auto value = voigtScalarProduct(material_.applyElasticityTensor(X1,localIndicatorFunction(quadPos)),matrixToVoigt(sym(prestrainPhaseValue))); elementPrestrain += value * quadPoint.weight() * integrationElement; // elementPrestrain += scalarProduct(material_.ElasticityTensor(X1,localIndicatorFunction(quadPos)),sym(prestrainPhaseValue)) * quadPoint.weight() * integrationElement; diff --git a/dune/microstructure/matrix_operations.hh b/dune/microstructure/matrix_operations.hh index 3eca389fe18d60c9f8d64df98f7aa18b7fb7aa9a..3cd76beddfeda08b1749c784afbe77ee6a9f40bb 100644 --- a/dune/microstructure/matrix_operations.hh +++ b/dune/microstructure/matrix_operations.hh @@ -9,26 +9,6 @@ namespace MatrixOperations { using std::sin; using std::cos; - static MatrixRT Id (){ - MatrixRT Id(0); - for (int i=0;i<3;i++) - Id[i][i]=1.0; - return Id; - } - - - static double norm(VectorRT v){ - return sqrt(pow(v[0],2) + pow(v[1],2) + pow(v[2],2)); - } - - static double norm(MatrixRT M){ - return sqrt( - pow(M[0][0],2) + pow(M[0][1],2) + pow(M[0][2],2) - + pow(M[1][0],2) + pow(M[1][1],2) + pow(M[1][2],2) - + pow(M[2][0],2) + pow(M[2][1],2) + pow(M[2][2],2)); - } - - // static MatrixRT sym (MatrixRT M) { // 1/2 (M^T + M) // MatrixRT ret(0); // for (int i = 0; i< 3; i++) @@ -159,10 +139,26 @@ namespace MatrixOperations { { R[2][0]*R[2][0], R[2][1]*R[2][1], R[2][2]*R[2][2], R[2][1]*R[2][2], R[2][0]*R[2][2], R[2][0]*R[2][1]}, {2.0*R[1][0]*R[2][0], 2.0*R[1][1]*R[2][1], 2.0*R[1][2]*R[2][2], R[1][1]*R[2][2]+R[1][2]*R[2][1], R[1][0]*R[2][2]+R[1][2]*R[2][0], R[1][0]*R[2][1]+R[1][1]*R[2][0]}, {2.0*R[0][0]*R[2][0], 2.0*R[0][1]*R[2][1], 2.0*R[0][2]*R[2][2], R[0][1]*R[2][2]+R[0][2]*R[2][1], R[0][0]*R[2][2]+R[0][2]*R[2][0], R[0][0]*R[2][1]+R[0][1]*R[2][0]}, - {2.0*R[0][0]*R[0][0], 2.0*R[0][1]*R[1][1], 2.0*R[0][2]*R[1][2], R[0][1]*R[1][2]+R[0][2]*R[1][1], R[0][0]*R[1][2]+R[0][2]*R[1][0], R[0][0]*R[1][1]+R[0][1]*R[1][0]} + {2.0*R[0][0]*R[1][0], 2.0*R[0][1]*R[1][1], 2.0*R[0][2]*R[1][2], R[0][1]*R[1][2]+R[0][2]*R[1][1], R[0][0]*R[1][2]+R[0][2]*R[1][0], R[0][0]*R[1][1]+R[0][1]*R[1][0]} }; } + + /** + * @brief Scale last three columns of stiffness matrix by a factor of 2. + * Inserting this facotr in the stiffness matrix allows to use the + * same Matrix-to-Vector mapping for both the stress and the strain. + * + * @param S Stiffness matrix + */ + static void scaleStiffnessMatrix(Dune::FieldMatrix<double,6,6>& S){ + for(size_t i = 0; i<6; i++) + for(size_t j = 3; j<6; j++) + { + S[i][j] = 2.0*S[i][j]; + } + } + // static double linearizedStVenantKirchhoffDensity(double mu, double lambda, MatrixRT E1, MatrixRT E2){ // ?? Check with Robert // E1= sym(E1); // E2 = sym(E2); @@ -181,7 +177,7 @@ namespace MatrixOperations { // // static double linearizedStVenantKirchhoffDensity(double mu, double lambda, MatrixRT E1, MatrixRT E2) // CHANGED { - auto t1 = 2.0 * mu * sym(E1) + lambda * trace(sym(E1)) * Id(); + auto t1 = 2.0 * mu * sym(E1) + MatrixRT(Dune::ScaledIdentityMatrix<double,3>(lambda * trace(sym(E1)))); auto tmp1 = scalarProduct(t1,sym(E2)); // auto tmp1 = scalarProduct(t1,E2); // auto t2 = 2.0 * mu * sym(E2) + lambda * trace(sym(E2)) * Id(); @@ -210,7 +206,7 @@ namespace MatrixOperations { static double QuadraticForm(const double mu, const double lambda, const MatrixRT M){ auto tmp1 = sym(M); - double tmp2 = norm(tmp1); + double tmp2 = tmp1.frobenius_norm(); // double tmp2 = norm(M); //TEST return lambda*std::pow(trace(M),2) + 2.0*mu*pow( tmp2 ,2); // return lambda*std::pow(trace(M),2) + 2*mu*pow( norm( sym(M) ),2); diff --git a/dune/microstructure/prestrainedMaterial.hh b/dune/microstructure/prestrainedMaterial.hh index 8651815aae24e8822f7cb3e4379cbdfae5c58fe9..deae82234e1553f7c3c0646f9e11b854e3b4fe01 100644 --- a/dune/microstructure/prestrainedMaterial.hh +++ b/dune/microstructure/prestrainedMaterial.hh @@ -98,28 +98,16 @@ public: using MatrixFunc = std::function< MatrixRT(const MatrixRT&) >; using MatrixPhase = std::function< MatrixRT(const int&) >; - // using VoigtMatrix = FieldMatrix< double, 6, 6>; - protected: const GridView& gridView_; const Dune::ParameterTree& parameterSet_; std::string materialFunctionName_; - // MatrixFunc L1_; - // MatrixFunc L2_; - // MatrixFunc L3_; - // Elasticity tensors (in Voigt notation) - Dune::FieldMatrix<double,6,6> L1_; - Dune::FieldMatrix<double,6,6> L2_; - Dune::FieldMatrix<double,6,6> L3_; - Dune::FieldMatrix<double,6,6> L4_; + std::vector<VoigtMatrix<double,3> > L_; - Func2Tensor prestrain1_; - Func2Tensor prestrain2_; - Func2Tensor prestrain3_; - Func2Tensor prestrain4_; + std::vector<Func2Tensor> prestrain_; Python::Module module_; @@ -129,7 +117,6 @@ protected: // Func2Tensor elasticityTensor_; // Func2TensorParam elasticityTensor_; Func2TensorPhase elasticityTensor_; - MatrixPhase prestrain_; Func2int indicatorFunction_; @@ -188,9 +175,9 @@ public: - // L1_ = orthotropic(e1,e2,e3,walnut_parameters); - // L2_ = orthotropic(e1,e2,e3,Nspruce_parameters); - // L3_ = orthotropic(e1,e2,e3,Nspruce_parameters); + // L_[0] = orthotropic(e1,e2,e3,walnut_parameters); + // L_[1] = orthotropic(e1,e2,e3,Nspruce_parameters); + // L_[2] = orthotropic(e1,e2,e3,Nspruce_parameters); setup(materialFunctionName_); // setup("material"); @@ -200,18 +187,18 @@ public: localIndicatorFunction_ = localFunction(indicatorFunctionGVF_); - // L1_ = transversely_isotropic(e1,e2,e3, {11.2e3,1190,960,0.63 ,0.37}); - // L2_ = transversely_isotropic(e1,e2,e3, {11.2e3,1190,960,0.63, 0.37}); - // L3_ = transversely_isotropic(e1,e2,e3, {10.7e3,710 ,500,0.51 ,0.31}); + // L_[0] = transversely_isotropic(e1,e2,e3, {11.2e3,1190,960,0.63 ,0.37}); + // L_[1] = transversely_isotropic(e1,e2,e3, {11.2e3,1190,960,0.63, 0.37}); + // L_[2] = transversely_isotropic(e1,e2,e3, {10.7e3,710 ,500,0.51 ,0.31}); - // L1_ = isotropic(mu[0],lambda[0]); - // L2_ = isotropic(mu[1],lambda[1]); - // L3_ = isotropic(mu[2],lambda[2]); + // L_[0] = isotropic(mu[0],lambda[0]); + // L_[1] = isotropic(mu[1],lambda[1]); + // L_[2] = isotropic(mu[2],lambda[2]); - // L1_ = {{lambda[0]+2.0*mu[0], lambda[0], lambda[0], 0.0 , 0.0, 0.0}, + // L_[0] = {{lambda[0]+2.0*mu[0], lambda[0], lambda[0], 0.0 , 0.0, 0.0}, // {lambda[0], lambda[0]+2*mu[0], lambda[0], 0.0 ,0.0 ,0.0}, // {lambda[0], lambda[0], lambda[0]+2.0*mu[0], 0.0, 0.0, 0.0}, // { 0.0 ,0.0, 0.0, 2.0*mu[0], 0.0, 0.0}, @@ -219,7 +206,7 @@ public: // { 0.0 ,0.0, 0.0, 0.0, 0.0, 2.0*mu[0]} // }; - // L2_ = {{lambda[1]+2.0*mu[1], lambda[1], lambda[1], 0.0 , 0.0, 0.0}, + // L_[1] = {{lambda[1]+2.0*mu[1], lambda[1], lambda[1], 0.0 , 0.0, 0.0}, // {lambda[1], lambda[1]+2*mu[1], lambda[1], 0.0 ,0.0 ,0.0}, // {lambda[1], lambda[1], lambda[1]+2.0*mu[1], 0.0, 0.0, 0.0}, // { 0.0 ,0.0, 0.0, 2.0*mu[1], 0.0, 0.0}, @@ -227,7 +214,7 @@ public: // { 0.0 ,0.0, 0.0, 0.0, 0.0, 2.0*mu[1]} // }; - // L3_ = {{lambda[2]+2.0*mu[2], lambda[2], lambda[2], 0.0 , 0.0, 0.0}, + // L_[2] = {{lambda[2]+2.0*mu[2], lambda[2], lambda[2], 0.0 , 0.0, 0.0}, // {lambda[2], lambda[2]+2.0*mu[2], lambda[2], 0.0 ,0.0 ,0.0}, // {lambda[2], lambda[2], lambda[2]+2.0*mu[2], 0.0, 0.0, 0.0}, // { 0.0 ,0.0, 0.0, 2.0*mu[2], 0.0, 0.0}, @@ -237,11 +224,11 @@ public: // printmatrix(std::cout, D_, "D_", "--"); // printmatrix(std::cout, D_inv, "D_inv", "--"); - // printmatrix(std::cout, L1_, "L1_", "--"); - // L1_.leftmultiply(D_inv); - // printmatrix(std::cout, L1_, "L1_.leftmultiply(D_inv)", "--"); - // L1_.rightmultiply(D_); - // printmatrix(std::cout, L1_, "L1_.rightmultiply(D_)", "--"); + // printmatrix(std::cout, L_[0], "L_[0]", "--"); + // L_[0].leftmultiply(D_inv); + // printmatrix(std::cout, L_[0], "L_[0].leftmultiply(D_inv)", "--"); + // L_[0].rightmultiply(D_); + // printmatrix(std::cout, L_[0], "L_[0].rightmultiply(D_)", "--"); // Python::Module module = Python::import(materialFunctionName_); @@ -251,9 +238,9 @@ public: // indicatorFunction_ = Python::make_function<int>(module.get("indicatorFunction")); // indicatorFunction_ = Dune::Functions::makeGridViewFunction(indicatorFunction , gridView_); // module.get("Phases").toC<int>(Phases_); - // L1_ = Python::make_function<MatrixRT>(module.get("L1")); - // L2_ = Python::make_function<MatrixRT>(module.get("L2")); - // L3_ = Python::make_function<MatrixRT>(module.get("L3")); + // L_[0] = Python::make_function<MatrixRT>(module.get("L1")); + // L_[1] = Python::make_function<MatrixRT>(module.get("L2")); + // L_[2] = Python::make_function<MatrixRT>(module.get("L3")); // bool isotropic_ = true; // read from module File // auto Test = Dune::Functions::makeGridViewFunction(MAT<Domain> , gridView_); //not working } @@ -278,7 +265,7 @@ Func2Tensor setupPrestrainPhase(Python::Module module, int phase){ module.get("phase" + std::to_string(phase) + "_axis").toC<int>(axis); module.get("phase" + std::to_string(phase) + "_angle").toC<double>(angle); } - catch(Dune::Exception) + catch(Dune::Exception&) { //default frame is used. } @@ -342,10 +329,10 @@ Dune::FieldMatrix<double,6,6> setupPhase(Python::Module module, int phase) module.get("phase" + std::to_string(phase) + "_axis").toC<int>(axis); module.get("phase" + std::to_string(phase) + "_angle").toC<double>(angle); } - catch(Dune::Exception) + catch(Dune::Exception& e) { // std::cout << "(Could not read frame vectors for material phase) " << phase << ": - Canonical Frame (default) is used." << std::endl; - std::cout << "(Could not read rotaton axis & angle for material phase) " << phase << ": - Canonical Frame (default) is used." << std::endl; + std::cout << "(Could not read rotation axis & angle for material phase) " << phase << ": - Canonical Frame (default) is used." << std::endl; } @@ -382,7 +369,7 @@ Dune::FieldMatrix<double,6,6> setupPhase(Python::Module module, int phase) * * @param name name of the material file being used. */ - void setup(const std::string name) // cant use materialFunctionName_ here? + void setup(const std::string name) // can't use materialFunctionName_ here? { Python::Module module = Python::import(name); indicatorFunction_ = Python::make_function<int>(module.get("indicatorFunction")); @@ -391,81 +378,15 @@ Dune::FieldMatrix<double,6,6> setupPhase(Python::Module module, int phase) module.get("Phases").toC<int>(phases); std::cout << "---- Starting material setup... (Number of Phases: "<< phases << ") " << std::endl; - switch (phases) - { - case 1: - { - // std::string phase1_type; - // module.get("phase1_type").toC<std::string>(phase1_type); + L_.resize(phases); + prestrain_.resize(phases); - L1_ = setupPhase(module,1); - // prestrain1_ = Python::make_function<MatrixRT>(module.get("prestrain_phase1")); - prestrain1_ = setupPrestrainPhase(module,1); - break; - } - case 2: - { - // std::string phase1_type; - // module.get("phase1_type").toC<std::string>(phase1_type); - // std::string phase2_type; - // module.get("phase2_type").toC<std::string>(phase2_type); - - L1_ = setupPhase(module,1); - L2_ = setupPhase(module,2); - // prestrain1_ = Python::make_function<MatrixRT>(module.get("prestrain_phase1")); - // prestrain2_ = Python::make_function<MatrixRT>(module.get("prestrain_phase2")); - prestrain1_ = setupPrestrainPhase(module,1); - prestrain2_ = setupPrestrainPhase(module,2); - break; - } - case 3: - { - // std::string phase1_type; - // module.get("phase1_type").toC<std::string>(phase1_type); - // std::string phase2_type; - // module.get("phase2_type").toC<std::string>(phase2_type); - // std::string phase3_type; - // module.get("phase3_type").toC<std::string>(phase3_type); - - L1_ = setupPhase(module,1); - L2_ = setupPhase(module,2); - L3_ = setupPhase(module,3); - // prestrain1_ = Python::make_function<MatrixRT>(module.get("prestrain_phase1")); - // prestrain2_ = Python::make_function<MatrixRT>(module.get("prestrain_phase2")); - // prestrain3_ = Python::make_function<MatrixRT>(module.get("prestrain_phase3")); - prestrain1_ = setupPrestrainPhase(module,1); - prestrain2_ = setupPrestrainPhase(module,2); - prestrain3_ = setupPrestrainPhase(module,3); - break; - } - case 4: - { - // std::string phase1_type; - // module.get("phase1_type").toC<std::string>(phase1_type); - // std::string phase2_type; - // module.get("phase2_type").toC<std::string>(phase2_type); - // std::string phase3_type; - // module.get("phase3_type").toC<std::string>(phase3_type); - // std::string phase4_type; - // module.get("phase4_type").toC<std::string>(phase4_type); - - L1_ = setupPhase(module,1); - L2_ = setupPhase(module,2); - L3_ = setupPhase(module,3); - L4_ = setupPhase(module,4); - // prestrain1_ = Python::make_function<MatrixRT>(module.get("prestrain_phase1")); - // prestrain2_ = Python::make_function<MatrixRT>(module.get("prestrain_phase2")); - // prestrain3_ = Python::make_function<MatrixRT>(module.get("prestrain_phase3")); - // prestrain4_ = Python::make_function<MatrixRT>(module.get("prestrain_phase4")); - prestrain1_ = setupPrestrainPhase(module,1); - prestrain2_ = setupPrestrainPhase(module,2); - prestrain3_ = setupPrestrainPhase(module,3); - prestrain4_ = setupPrestrainPhase(module,4); - break; - } - default: - DUNE_THROW(Dune::Exception, " No more than 4 material phases are implemented yet! "); + for (int i=0; i<phases; i++) + { + L_[i] = setupPhase(module,i+1); + prestrain_[i] = setupPrestrainPhase(module, i+1); } + std::cout << "Material setup done." << std::endl; } @@ -474,15 +395,15 @@ Dune::FieldMatrix<double,6,6> setupPhase(Python::Module module, int phase) // MATERIAL CLASSES DEFINITIONS: //////////////////////////////////////////////////////// - //--- Definition of isotropic elasticity tensor (stiffness matrix in voigt notation) + /** \brief Isotropic stiffness matrix in Voigt notation but scaled by a factor of 2 in the last three columns. */ Dune::FieldMatrix<double,6,6> isotropic(const double& mu, const double& lambda) { - return {{lambda+2.0*mu, lambda , lambda , 0.0 , 0.0 , 0.0 }, - {lambda , lambda+2.0*mu, lambda , 0.0 , 0.0 , 0.0 }, - {lambda , lambda , lambda+2.0*mu, 0.0 , 0.0 , 0.0 }, - { 0.0 , 0.0 , 0.0 , mu , 0.0 , 0.0 }, - { 0.0 , 0.0 , 0.0 , 0.0 , mu , 0.0 }, - { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , mu } + return {{lambda+2.0*mu, lambda , lambda , 0.0 , 0.0 , 0.0 }, + {lambda , lambda+2.0*mu, lambda , 0.0 , 0.0 , 0.0 }, + {lambda , lambda , lambda+2.0*mu, 0.0 , 0.0 , 0.0 }, + { 0.0 , 0.0 , 0.0 , 2.0*mu, 0.0 , 0.0 }, + { 0.0 , 0.0 , 0.0 , 0.0 , 2.0*mu, 0.0 }, + { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 2.0*mu } }; } //------------------------------------------------------------------------------- @@ -555,12 +476,14 @@ Dune::FieldMatrix<double,6,6> setupPhase(Python::Module module, int phase) (Compliance.leftmultiply(C_rot)).rightmultiply(C_rot.transposed()); } - printmatrix(std::cout, Compliance, "Compliance matrix used:", "--"); - // invert to obtain elasticity/stiffness-Tensor + // invert Compliance matrix to obtain elasticity/stiffness matrix Compliance.invert(); // printmatrix(std::cout, Compliance, "Stiffness Tensor", "--"); + scaleStiffnessMatrix(Compliance); + // printmatrix(std::cout, Compliance, "Stiffness Tensor scaled", "--"); + // printmatrix(std::cout, Compliance, "Stiffness Tensor", "--"); return Compliance; } //------------------------------------------------------------------------------- @@ -627,7 +550,10 @@ Dune::FieldMatrix<double,6,6> setupPhase(Python::Module module, int phase) //--- return elasticity tensor Compliance.invert(); - // printmatrix(std::cout, C, "C after .invert()", "--"); + // printmatrix(std::cout, Compliance, "Stiffness Tensor", "--"); + + scaleStiffnessMatrix(Compliance); + return Compliance; } //------------------------------------------------------------------------------- @@ -667,85 +593,35 @@ Dune::FieldMatrix<double,6,6> setupPhase(Python::Module module, int phase) } printmatrix(std::cout, Compliance, "Compliance matrix used:", "--"); - //--- return elasticity tensor (in Voigt notation) + + + + //--- return stiffness/elasticity tensor (in Voigt notation) Compliance.invert(); - // printmatrix(std::cout, C, "C after .invert()", "--"); + // printmatrix(std::cout, Compliance, "Stiffness Tensor", "--"); + + scaleStiffnessMatrix(Compliance); + return Compliance; } //------------------------------------------------------------------------------- - MatrixRT applyElasticityTensor(const MatrixRT& G, const int& phase) const + VoigtVector<double,3> applyElasticityTensor(const VoigtVector<double,3>& G, const int& phase) const { - - VoigtVector<double,3> G_tmp = strainToVoigt(G); VoigtVector<double,3> out(0); - switch (phase) - { - case 1: - { - // printmatrix(std::cout, L1_, "L1_", "--"); - L1_.mv(G_tmp,out); - break; - } - case 2: - { - // printmatrix(std::cout, L2_, "L2_", "--"); - L2_.mv(G_tmp,out); - break; - } - case 3: - { - // printmatrix(std::cout, L3_, "L3_", "--"); - L3_.mv(G_tmp,out); - break; - } - case 4: - { - // printmatrix(std::cout, L4_, "L4_", "--"); - L4_.mv(G_tmp,out); - break; - } - default: - DUNE_THROW(Dune::Exception, "Phase number not implemented."); - break; - } - - return voigtToStress(out); + // printmatrix(std::cout, L_[0], "L_[0]", "--"); + L_[phase-1].mv(G,out); + return out; } //////////////////////////////////////////////////////////////////////////////////////// MatrixRT prestrain(const int& phase,const Domain& x) const { - switch (phase) - { - case 1: - { - return prestrain1_(x); - break; - } - case 2: - { - return prestrain2_(x); - break; - } - case 3: - { - return prestrain3_(x); - break; - } - case 4: - { - return prestrain3_(x); - break; - } - default: - DUNE_THROW(Dune::Exception, "Phase number not implemented."); - break; - } + return prestrain_[phase-1](x); } diff --git a/dune/microstructure/voigthelper.hh b/dune/microstructure/voigthelper.hh index db0bf17c49e3049950de77900f77c5d16ee826d0..5058f710ec2b21a535b8da7f51aec7082d498646 100644 --- a/dune/microstructure/voigthelper.hh +++ b/dune/microstructure/voigthelper.hh @@ -16,28 +16,49 @@ template<typename T, int dim> using VoigtMatrix = Dune::FieldMatrix<T,dim*(dim+1)/2,dim*(dim+1)/2>; +/** + * @brief Voigt-notation(https://de.wikipedia.org/wiki/Voigtsche_Notation) distinguishes + * in the transformation from Matrix to Vector between stresses and strains. The transformation + * for strains features an additional factor 2 for the non-diagonal entries. In order to avoid + * the use of different data structures for both stresses & strains we use the same Matrix-to-Vector + * mapping ('matrixToVoigt') and incorporate the factors in suitable places. namely: + * - The Stiffness matrix of the constitutive relation get scaled by a factor of 2 in the last three columns + * - The 'voigtScalarProduct' scales the lase three products by a factor of 2 + */ + template<typename T> -static VoigtVector<T,3> strainToVoigt(const Dune::FieldMatrix<T,3,3>& G) +VoigtVector<T,3> matrixToVoigt(const Dune::FieldMatrix<T,3,3>& matrix) { - return {G[0][0], G[1][1], G[2][2], 2.0*G[1][2], 2.0*G[0][2], 2.0*G[0][1]}; + return {matrix[0][0], matrix[1][1], matrix[2][2], matrix[1][2], matrix[0][2], matrix[0][1]}; } template<typename T> -static Dune::FieldMatrix<T,3,3> voigtToStrain(const VoigtVector<T,3>& v) +Dune::FieldMatrix<T,3,3> voigtToMatrix(const VoigtVector<T,3>& v) { - return {{v[0], v[5]/2.0, v[4]/2.0}, {v[5]/2.0, v[1], v[3]/2.0}, {v[4]/2.0, v[3]/2.0, v[2]}}; + return {{v[0], v[5], v[4]}, {v[5], v[1], v[3]}, {v[4], v[3], v[2]}}; } +/** \brief Interpret Voigt vectors as symmetric matrices and compute their Frobenius scalar voigtScalarProduct + */ template<typename T> -static VoigtVector<T,3> stressToVoigt(const Dune::FieldMatrix<T,3,3>& G) +T voigtScalarProduct(const VoigtVector<T,3>& a, const VoigtVector<T,3>& b) { - return {G[0][0], G[1][1], G[2][2], G[1][2], G[0][2], G[0][1]}; + return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + 2.0*a[3]*b[3] + 2.0*a[4]*b[4] + 2.0*a[5]*b[5]; } +/** \brief Return the symmetric part of a matrix, in Voigt notation */ template<typename T> -static Dune::FieldMatrix<T,3,3> voigtToStress(const VoigtVector<T,3>& v) +VoigtVector<T,3> symVoigt(const Dune::FieldMatrix<T,3,3>& matrix) { - return {{v[0], v[5], v[4]}, {v[5], v[1], v[3]}, {v[4], v[3], v[2]}}; + VoigtVector<T,3> result = {matrix[0][0], + matrix[1][1], + matrix[2][2], + // The 0.5 is part of the sym operator, the 2.0 is from the conversion to Voigt notation + 0.5 * (matrix[1][2] + matrix[2][1]), + 0.5 * (matrix[0][2] + matrix[2][0]), + 0.5 * (matrix[0][1] + matrix[1][0])}; + + return result; } #endif // DUNE_MICROSTRUCTURE_VOIGTHELPER_HH