diff --git a/src/rodassembler.cc b/src/rodassembler.cc index 27d4b7169a69c2ab408dc73888acc82065b89719..074a14f6331ae0c2821c863fd07061706bf35f14 100644 --- a/src/rodassembler.cc +++ b/src/rodassembler.cc @@ -117,7 +117,7 @@ getLocalMatrix( EntityPointer &entity, const QuadratureRule<double, gridDim>& quad = QuadratureRules<double, gridDim>::rule(entity->type(), polOrd); /* Loop over all integration points */ - for (int ip=0; ip<quad.size(); ip++) { + for (size_t ip=0; ip<quad.size(); ip++) { // Local position of the quadrature point const FieldVector<double,gridDim>& quadPos = quad[ip].position(); @@ -132,7 +132,7 @@ getLocalMatrix( EntityPointer &entity, /**********************************************/ /* compute gradients of the shape functions */ /**********************************************/ - FieldVector<double,gridDim> shapeGrad[ndof]; + FieldVector<double,gridDim> shapeGrad[2]; FieldVector<double,gridDim> tmp; for (int dof=0; dof<ndof; dof++) { @@ -147,7 +147,7 @@ getLocalMatrix( EntityPointer &entity, } - double shapeFunction[matSize]; + FieldVector<double,1> shapeFunction[matSize]; for(int i=0; i<matSize; i++) shapeFunction[i] = baseSet[i].evaluateFunction(0,quadPos); @@ -219,7 +219,7 @@ getLocalMatrix( EntityPointer &entity, for (int a=0; a<4; a++) for (int b=0; b<4; b++) A[a][b] = (q.mult(dq_dvj[l]))[a] * (q.mult(dq_dvj[j]))[b] - + q[a] * q.mult(dq_dvj_dvl[j][l])[b]; + + q[a] * q.mult(dq_dvj_dvl[l][j])[b]; // d1 dd_dvij_dvkl[0][j][l][0] = A[0][0] - A[1][1] - A[2][2] + A[3][3]; @@ -264,7 +264,6 @@ getLocalMatrix( EntityPointer &entity, for (int j=0; j<3; j++) { for (int m=0; m<3; m++) { - //du_dvij[i][j][m] = 2 * (hatq.mult(dq_dvj[j])).B(m)*hatq_s * shapeFunction[i]; du_dvij[i][j][m] = (q.mult(dq_dvj[j])).B(m)*q_s; du_dvij[i][j][m] *= 2 * shapeFunction[i]; Quaternion<double> tmp = dq_dvj[j]; @@ -272,6 +271,7 @@ getLocalMatrix( EntityPointer &entity, du_dvij[i][j][m] += 2 * ( q.B(m)*(q.mult(dq_dvij_ds[i][j]) + q_s.mult(tmp))); } +#if 0 for (int k=0; k<2; k++) { for (int l=0; l<3; l++) { @@ -282,10 +282,10 @@ getLocalMatrix( EntityPointer &entity, tmp_ij *= shapeFunction[i]; tmp_kl *= shapeFunction[k]; - for (int m=0; m<3; m++) { + Quaternion<double> tmp_ijkl = dq_dvj_dvl[j][l]; + tmp_ijkl *= shapeFunction[i] * shapeFunction[k]; - Quaternion<double> tmp_ijkl = dq_dvj_dvl[j][l]; - tmp_ijkl *= shapeFunction[i] * shapeFunction[k]; + for (int m=0; m<3; m++) { du_dvij_dvkl[i][j][k][l][m] = 2 * ( (q.mult(tmp_ijkl)).B(m) * q_s) + 2 * ( (q.mult(tmp_ij)).B(m) * (q.mult(dq_dvij_ds[k][l]) + q_s.mult(tmp_kl))) @@ -297,7 +297,16 @@ getLocalMatrix( EntityPointer &entity, } } - +#else +#warning Using fd approximation of rotation strain Hessian. + Dune::array<Dune::Matrix<Dune::FieldMatrix<double,3,3> >, 3> rotationHessian; + rotationStrainHessian(localSolution, quadPos[0], shapeGrad, shapeFunction, rotationHessian); + for (int k=0; k<2; k++) + for (int l=0; l<3; l++) + for (int m=0; m<3; m++) + du_dvij_dvkl[i][j][k][l][m] = rotationHessian[m][i][k][j][l]; +#endif + } } @@ -305,6 +314,9 @@ getLocalMatrix( EntityPointer &entity, // /////////////////////////////////// // Sum it all up // /////////////////////////////////// + array<FieldMatrix<double,2,6>, 6> strainDerivatives; + strainDerivative(localSolution, quadPos[0], shapeGrad, shapeFunction, strainDerivatives); + for (int i=0; i<matSize; i++) { for (int k=0; k<matSize; k++) { @@ -324,13 +336,14 @@ getLocalMatrix( EntityPointer &entity, * A_[m] * shapeGrad[i] * q.director(m)[j] * shapeGrad[k] * q.director(m)[l]; // \partial W^2 \partial v^i_j \partial r^k_l - localMat[i][k][j][l+3] += weight - * ( A_[m] * shapeGrad[k]*q.director(m)[l]*(r_s*dd_dvj[m][j] * shapeFunction[i]) + localMat[i][k][j+3][l] += weight + * ( A_[m] * strainDerivatives[m][k][l] * strainDerivatives[m][i][j+3] + A_[m] * (strain[m] - referenceStrain[m]) * shapeGrad[k] * dd_dvj[m][j][l]*shapeFunction[i]); - // This is programmed stupidly. To ensure the symmetry it is enough to make - // the following assignment once and not for each quadrature point - localMat[k][i][l+3][j] = localMat[i][k][j][l+3]; + // \partial W^2 \partial r^i_j \partial v^k_l + localMat[i][k][j][l+3] += weight + * ( A_[m] * strainDerivatives[m][i][j] * strainDerivatives[m][k][l+3] + + A_[m] * (strain[m] - referenceStrain[m]) * shapeGrad[i] * dd_dvj[m][l][j]*shapeFunction[k]); // \partial W^2 \partial v^i_j \partial v^k_l localMat[i][k][j+3][l+3] += weight @@ -361,9 +374,282 @@ getLocalMatrix( EntityPointer &entity, } } + +} + +template <class GridType> +void Dune::RodAssembler<GridType>:: +strainDerivative(const std::vector<Configuration>& localSolution, + double pos, + FieldVector<double,1> shapeGrad[2], + FieldVector<double,1> shapeFunction[2], + Dune::array<FieldMatrix<double,2,6>, 6>& derivatives) const +{ + assert(localSolution.size()==2); + +// FieldVector<double,1> shapeGrad[2]; +// shapeGrad[0] = -1; +// shapeGrad[1] = 1; + +// FieldVector<double,1> shapeFunction[2]; +// shapeFunction[0] = 1-pos; +// shapeFunction[1] = pos; + + + FieldVector<double,3> r_s; + for (int i=0; i<3; i++) + r_s[i] = localSolution[0].r[i]*shapeGrad[0] + localSolution[1].r[i]*shapeGrad[1]; + + // Interpolate current rotation at this quadrature point + Quaternion<double> q = Quaternion<double>::interpolate(localSolution[0].q, localSolution[1].q,pos); + + // Contains \parder d \parder v^i_j + array<array<FieldVector<double,3>, 3>, 3> dd_dvj; + q.getFirstDerivativesOfDirectors(dd_dvj); + + Quaternion<double> q_s = Quaternion<double>::interpolateDerivative(localSolution[0].q, localSolution[1].q, + pos, 1/shapeGrad[1]); + + array<Quaternion<double>,3> dq_dvj; + Quaternion<double> dq_dvij_ds[2][3]; + for (int i=0; i<2; i++) + for (int j=0; j<3; j++) { + + for (int m=0; m<3; m++) { + dq_dvj[j][m] = (j==m) * 0.5; + dq_dvij_ds[i][j][m] = (j==m) * 0.5 * shapeGrad[i]; + } + + dq_dvj[j][3] = 0; + dq_dvij_ds[i][j][3] = 0; + } + + // the strain component + for (int m=0; m<3; m++) { + + // the shape function + for (int i=0; i<2; i++) { + + // the partial derivative direction + for (int j=0; j<3; j++) { + + // parder v_m / \partial r^j_i + derivatives[m][i][j] = shapeGrad[i]*q.director(m)[j]; + + derivatives[m][i][j+3] = r_s *dd_dvj[m][j] * shapeFunction[i]; + + // \partial u_m + derivatives[m+3][i][j] = 0; + + double du_dvij_i_j_m = 2* ((q.mult(dq_dvj[j])).B(m)*q_s) * shapeFunction[i][0]; + Quaternion<double> tmp = dq_dvj[j]; + tmp *= shapeFunction[i]; +#if 1 + du_dvij_i_j_m += 2 * ( q.B(m)*(q.mult(dq_dvij_ds[i][j]) + q_s.mult(tmp))); +#else +#warning Term omitted in strainDerivative +#endif + derivatives[m+3][i][j+3] = du_dvij_i_j_m; + + } + + } + + } + + +} + + +template <class GridType> +void Dune::RodAssembler<GridType>:: +strainHessian(const std::vector<Configuration>& localSolution, + double pos, + Dune::array<Matrix<FieldMatrix<double,6,6> >, 3>& translationDer, + Dune::array<Matrix<FieldMatrix<double,3,3> >, 3>& rotationDer) const +{ + assert(localSolution.size()==2); + + FieldVector<double,1> shapeGrad[2]; + shapeGrad[0] = -1; + shapeGrad[1] = 1; + + FieldVector<double,1> shapeFunction[2]; + shapeFunction[0] = 1-pos; + shapeFunction[1] = pos; + + + FieldVector<double,3> r_s; + for (int i=0; i<3; i++) + r_s[i] = localSolution[0].r[i]*shapeGrad[0] + localSolution[1].r[i]*shapeGrad[1]; + + // Interpolate current rotation at this quadrature point + Quaternion<double> q = Quaternion<double>::interpolate(localSolution[0].q, localSolution[1].q,pos); + + // Contains \parder d \parder v^i_j + array<array<FieldVector<double,3>, 3>, 3> dd_dvj; + q.getFirstDerivativesOfDirectors(dd_dvj); + + Quaternion<double> q_s = Quaternion<double>::interpolateDerivative(localSolution[0].q, localSolution[1].q, + pos, 1/shapeGrad[1]); + + array<Quaternion<double>,3> dq_dvj; + Quaternion<double> dq_dvij_ds[2][3]; + for (int i=0; i<2; i++) + for (int j=0; j<3; j++) { + + for (int m=0; m<3; m++) { + dq_dvj[j][m] = (j==m) * 0.5; + dq_dvij_ds[i][j][m] = (j==m) * 0.5 * shapeGrad[i]/* * ((i==0) ? 1-pos[0] : pos[0])*/; + } + + dq_dvj[j][3] = 0; + dq_dvij_ds[i][j][3] = 0; + } + + Quaternion<double> dq_dvj_dvl[3][3]; + Quaternion<double> dq_dvij_dvkl_ds[2][3][2][3]; + for (int i=0; i<2; i++) { + + for (int j=0; j<3; j++) { + + for (int k=0; k<2; k++) { + + for (int l=0; l<3; l++) { + + for (int m=0; m<3; m++) { + dq_dvj_dvl[j][l][m] = 0; + dq_dvij_dvkl_ds[i][j][k][l][m] = 0; + } + + dq_dvj_dvl[j][l][3] = -0.25 * (j==l); + dq_dvij_dvkl_ds[i][j][k][l][3] = -0.25 * (j==l) * shapeGrad[i] * shapeGrad[k] + /* * ((i==0) ? 1-pos[0] : pos[0]) * ((k==0) ? 1-pos[0] : pos[0]) */; + + } + + } + + } + + } + + // the strain component + for (int m=0; m<3; m++) { + + translationDer[m].setSize(2,2); + translationDer[m] = 0; + + rotationDer[m].setSize(2,2); + rotationDer[m] = 0; + + // the shape function + for (int i=0; i<2; i++) { + + // the partial derivative direction + for (int j=0; j<3; j++) { + + for (int k=0; k<2; k++) { + + for (int l=0; l<3; l++) { + + + + // ////////////////////////////////////////////////// + // The rotation part + // ////////////////////////////////////////////////// + Quaternion<double> tmp_ij = dq_dvj[j]; + Quaternion<double> tmp_kl = dq_dvj[l]; + + tmp_ij *= shapeFunction[i]; + tmp_kl *= shapeFunction[k]; + + Quaternion<double> tmp_ijkl = dq_dvj_dvl[j][l]; + tmp_ijkl *= shapeFunction[i] * shapeFunction[k]; + + rotationDer[m][i][k][j][l] = 2 * ( (q.mult(tmp_ijkl)).B(m) * q_s); + rotationDer[m][i][k][j][l] += 2 * ( (q.mult(tmp_ij)).B(m) * (q.mult(dq_dvij_ds[k][l]) + q_s.mult(tmp_kl))); +#if 1 + rotationDer[m][i][k][j][l] += 2 * ( (q.mult(tmp_kl)).B(m) * (q.mult(dq_dvij_ds[i][j]) + q_s.mult(tmp_ij))); + rotationDer[m][i][k][j][l] += 2 * ( q.B(m) * (q.mult(dq_dvij_dvkl_ds[i][j][k][l]) + q_s.mult(tmp_ijkl))); +#else +#warning Term omitted in strainHessian +#endif + + } + + } + + } + + } + + } + + +} + +template <class GridType> +void Dune::RodAssembler<GridType>:: +rotationStrainHessian(const std::vector<Configuration>& x, + double pos, + Dune::FieldVector<double,1> shapeGrad[2], + Dune::FieldVector<double,1> shapeFunction[2], + Dune::array<Dune::Matrix<Dune::FieldMatrix<double,3,3> >, 3>& rotationDer) const +{ + assert(x.size()==2); + double eps = 1e-3; + + for (int m=0; m<3; m++) { + + rotationDer[m].setSize(2,2); + rotationDer[m] = 0; + + } + + // /////////////////////////////////////////////////////////// + // Compute gradient by finite-difference approximation + // /////////////////////////////////////////////////////////// + std::vector<Configuration> forwardSolution = x; + std::vector<Configuration> backwardSolution = x; + + for (int k=0; k<2; k++) { + + for (int l=0; l<3; l++) { + + // infinitesimalVariation(forwardSolution[k], eps, l+3); +// infinitesimalVariation(backwardSolution[k], -eps, l+3); + forwardSolution[k].q = forwardSolution[k].q.mult(Quaternion<double>::exp((l==0)*eps, + (l==1)*eps, + (l==2)*eps)); + backwardSolution[k].q = backwardSolution[k].q.mult(Quaternion<double>::exp(-(l==0)*eps, + -(l==1)*eps, + -(l==2)*eps)); + + Dune::array<Dune::FieldMatrix<double,2,6>, 6> forwardStrainDer; + strainDerivative(forwardSolution, pos, shapeGrad, shapeFunction, forwardStrainDer); + + Dune::array<Dune::FieldMatrix<double,2,6>, 6> backwardStrainDer; + strainDerivative(backwardSolution, pos, shapeGrad, shapeFunction, backwardStrainDer); + + for (int i=0; i<2; i++) { + for (int j=0; j<3; j++) { + for (int m=0; m<3; m++) { + rotationDer[m][i][k][j][l] = (forwardStrainDer[m][i][j]-backwardStrainDer[m][i][j]) / (2*eps); + } + } + } + + forwardSolution = x; + backwardSolution = x; + + } + + } } + template <class GridType> void Dune::RodAssembler<GridType>:: assembleGradient(const std::vector<Configuration>& sol, @@ -780,7 +1066,8 @@ Dune::FieldVector<double, 6> Dune::RodAssembler<GridType>::getStrain(const std:: template <class GridType> Dune::FieldVector<double,3> Dune::RodAssembler<GridType>:: getResultantForce(const BoundaryPatch<GridType>& boundary, - const std::vector<Configuration>& sol) const + const std::vector<Configuration>& sol, + FieldVector<double,3>& canonicalTorque) const { const typename GridType::Traits::LeafIndexSet& indexSet = grid_->leafIndexSet(); @@ -788,7 +1075,8 @@ getResultantForce(const BoundaryPatch<GridType>& boundary, DUNE_THROW(Exception, "Solution vector doesn't match the grid!"); FieldVector<double,3> canonicalStress(0); - + canonicalTorque = 0; + // Loop over the given boundary ElementLeafIterator eIt = grid_->template leafbegin<0>(); ElementLeafIterator eEndIt = grid_->template leafend<0>(); @@ -817,6 +1105,10 @@ getResultantForce(const BoundaryPatch<GridType>& boundary, for (int i=0; i<3; i++) localStress[i] = (strain[i] - referenceStrain[i]) * A_[i]; + FieldVector<double,3> localTorque; + for (int i=0; i<3; i++) + localTorque[i] = (strain[i+3] - referenceStrain[i+3]) * K_[i]; + // Transform stress given with respect to the basis given by the three directors to // the canonical basis of R^3 /** \todo Hardwired: Entry 0 is the leftmost entry! */ @@ -825,6 +1117,7 @@ getResultantForce(const BoundaryPatch<GridType>& boundary, orientationMatrix.umv(localStress, canonicalStress); + orientationMatrix.umv(localTorque, canonicalTorque); // Reverse transformation to make sure we did the correct thing // assert( std::abs(localStress[0]-canonicalStress*sol[0].q.director(0)) < 1e-6 ); // assert( std::abs(localStress[1]-canonicalStress*sol[0].q.director(1)) < 1e-6 ); @@ -837,10 +1130,3 @@ getResultantForce(const BoundaryPatch<GridType>& boundary, return canonicalStress; } -template <class GridType> -Dune::FieldVector<double,3> Dune::RodAssembler<GridType>:: -getResultantTorque(const BoundaryPatch<GridType>& boundary, - const std::vector<Configuration>& sol) const -{ -#warning getResultantForce non implemented yet! -} diff --git a/src/rodassembler.hh b/src/rodassembler.hh index 785e2bf2cd565f2096992f87cf2c483947c3811c..106dc3153db86c94d5eaed73bf3276a90ed29e66 100644 --- a/src/rodassembler.hh +++ b/src/rodassembler.hh @@ -33,6 +33,8 @@ namespace Dune //! typedef FieldMatrix<double, blocksize, blocksize> MatrixBlock; + /** \todo public only for debugging! */ + public: const GridType* grid_; /** \brief Material constants */ @@ -108,7 +110,24 @@ namespace Dune */ void assembleMatrix(const std::vector<Configuration>& sol, BCRSMatrix<MatrixBlock>& matrix) const; + + void strainDerivative(const std::vector<Configuration>& localSolution, + double pos, + FieldVector<double,1> shapeGrad[2], + FieldVector<double,1> shapeFunction[2], + Dune::array<FieldMatrix<double,2,6>, 6>& derivatives) const; + + void rotationStrainHessian(const std::vector<Configuration>& x, + double pos, + FieldVector<double,1> shapeGrad[2], + FieldVector<double,1> shapeFunction[2], + Dune::array<Dune::Matrix<Dune::FieldMatrix<double,3,3> >, 3>& rotationDer) const; + void strainHessian(const std::vector<Configuration>& localSolution, + double pos, + Dune::array<Matrix<FieldMatrix<double,6,6> >, 3>& translationDer, + Dune::array<Matrix<FieldMatrix<double,3,3> >, 3>& rotationDer) const; + void assembleGradient(const std::vector<Configuration>& sol, BlockVector<FieldVector<double, blocksize> >& grad) const; @@ -130,13 +149,8 @@ namespace Dune \note Linear run-time in the size of the grid */ FieldVector<double,3> getResultantForce(const BoundaryPatch<GridType>& boundary, - const std::vector<Configuration>& sol) const; - - /** \brief Return resultant torque across boundary in canonical coordinates - - \note Linear run-time in the size of the grid */ - FieldVector<double,3> getResultantTorque(const BoundaryPatch<GridType>& boundary, - const std::vector<Configuration>& sol) const; + const std::vector<Configuration>& sol, + FieldVector<double,3>& canonicalTorque) const; protected: