From 26e4db8c209ff6fdd2301bbe72d007883ba30f9b Mon Sep 17 00:00:00 2001 From: Elias Pipping <elias.pipping@fu-berlin.de> Date: Mon, 9 Mar 2015 17:37:34 +0100 Subject: [PATCH] [Bug fix] Fix normal stress computation * Use PointTractionBoundaryAssembler: The normal stress is properly calculated here * Incorporate weights into normal stress --- .../pointtractionboundaryassembler.hh | 146 ++++++++++++++++++ src/assemblers.cc | 32 ++-- src/assemblers.hh | 10 +- src/program_state.hh | 12 +- src/sand-wedge.cc | 2 +- 5 files changed, 175 insertions(+), 27 deletions(-) create mode 100644 dune/tectonic/pointtractionboundaryassembler.hh diff --git a/dune/tectonic/pointtractionboundaryassembler.hh b/dune/tectonic/pointtractionboundaryassembler.hh new file mode 100644 index 00000000..648ec7e2 --- /dev/null +++ b/dune/tectonic/pointtractionboundaryassembler.hh @@ -0,0 +1,146 @@ +#ifndef DUNE_TECTONIC_POINTTRACTIONBOUNDARYASSEMBLER_HH +#define DUNE_TECTONIC_POINTTRACTIONBOUNDARYASSEMBLER_HH + +// Based on +// dune/fufem/assemblers/localassemblers/normalstressboundaryassembler.hh + +#include <dune/common/fvector.hh> +#include <dune/geometry/quadraturerules.hh> +#include <dune/istl/bvector.hh> + +#include <dune/fufem/assemblers/localboundaryassembler.hh> +#include <dune/fufem/symmetrictensor.hh> +#include <dune/fufem/functions/virtualgridfunction.hh> +#include <dune/fufem/quadraturerules/quadraturerulecache.hh> + +/** \brief Computes the surface traction of a linear elastic material, + pointwise. This is done in such a manner that the sum over all + vertices equals the (approximate) integral */ +template <class GridType> +class PointTractionBoundaryAssembler + : public LocalBoundaryAssembler< + GridType, + Dune::FieldVector<typename GridType::ctype, GridType::dimension>> { + static const int dim = GridType::dimension; + typedef typename GridType::ctype ctype; + typedef typename Dune::FieldVector<ctype, dim> T; + +public: + typedef typename LocalBoundaryAssembler<GridType, T>::LocalVector LocalVector; + typedef VirtualGridFunction< + GridType, Dune::FieldVector<ctype, GridType::dimension>> GridFunction; + + //! Create assembler for grid + PointTractionBoundaryAssembler(double E, double nu, + const GridFunction* displacement, int order) + : E_(E), nu_(nu), displacement_(displacement), order_(order) {} + + /** \brief Assemble the normal stress at a boundary face.*/ + template <class TrialLocalFE, class BoundaryIterator> + void assemble(const BoundaryIterator& it, LocalVector& localVector, + const TrialLocalFE& tFE) { + + localVector = 0.0; + + // geometry of the boundary face + const typename BoundaryIterator::Intersection::Geometry segmentGeometry = + it->geometry(); + + // get quadrature rule + const int order = (it->inside()->type().isSimplex()) + ? 2 * (order_ - 1) + : 2 * (order_ * dim - 1); + + // get quadrature rule + const Dune::QuadratureRule<ctype, dim - 1>& quad = + QuadratureRuleCache<ctype, dim - 1>::rule(segmentGeometry.type(), order, + false); + + // loop over quadrature points + for (size_t pt = 0; pt < quad.size(); ++pt) { + // get quadrature point + const Dune::FieldVector<ctype, dim - 1>& quadPos = quad[pt].position(); + + // get integration factor + const ctype integrationElement = + segmentGeometry.integrationElement(quadPos); + + // get outer unit normal at quad pos + Dune::FieldVector<ctype, dim> normalAtQuadPos = + it->unitOuterNormal(quadPos); + + // position of the quadrature point within the element + const Dune::FieldVector<ctype, dim> elementQuadPos = + it->geometryInInside().global(quadPos); + + // evaluate the displacement gradient at quad point of the element + typename GridFunction::DerivativeType localDispGradient; + if (displacement_->isDefinedOn(*it->inside())) + displacement_->evaluateDerivativeLocal(*it->inside(), elementQuadPos, + localDispGradient); + else + displacement_->evaluateDerivative(segmentGeometry.global(quadPos), + localDispGradient); + + // Compute strain tensor from the displacement gradient + SymmetricTensor<dim> strain; + computeStrain(localDispGradient, strain); + + // and the stress + SymmetricTensor<dim> stress = hookeTimesStrain(strain); + + normalAtQuadPos *= quad[pt].weight() * integrationElement; + typename LocalVector::block_type tractionAtQuadPos; + stress.umv(normalAtQuadPos, tractionAtQuadPos); + + // Divide the traction + tractionAtQuadPos /= segmentGeometry.corners(); + + for (size_t k = 0; k < localVector.size(); k++) + localVector[k] += tractionAtQuadPos; + } + } + + ~PointTractionBoundaryAssembler() {} + +private: + /** \brief Young's modulus */ + double E_; + + /** \brief The Poisson ratio */ + double nu_; + + /** \brief The displacement.*/ + const GridFunction* displacement_; + + /** \brief The gridfunction is usually corresponding to some finite element + * solution. This is its order.*/ + int order_; + + /** \brief Compute linear strain tensor from the deformation gradient. */ + void computeStrain(const Dune::FieldMatrix<double, dim, dim>& grad, + SymmetricTensor<dim>& strain) const { + for (int i = 0; i < dim; ++i) { + strain(i, i) = grad[i][i]; + for (int j = i + 1; j < dim; ++j) + strain(i, j) = 0.5 * (grad[i][j] + grad[j][i]); + } + } + + /** \brief Compute the stress tensor from strain tensor. */ + SymmetricTensor<dim> hookeTimesStrain( + const SymmetricTensor<dim>& strain) const { + + SymmetricTensor<dim> stress = strain; + stress *= E_ / (1 + nu_); + + double f = E_ * nu_ / ((1 + nu_) * (1 - 2 * nu_)) * strain.trace(); + + for (int i = 0; i < dim; i++) + stress[i] += f; + + return stress; + } +}; + +#endif diff --git a/src/assemblers.cc b/src/assemblers.cc index 1dc59593..7eb63cf8 100644 --- a/src/assemblers.cc +++ b/src/assemblers.cc @@ -12,13 +12,13 @@ #include <dune/fufem/assemblers/localassemblers/vonmisesstressassembler.hh> #include <dune/fufem/assemblers/localassemblers/weightedmassassembler.hh> #include <dune/fufem/boundarypatch.hh> -#include <dune/fufem/computestress.hh> #include <dune/fufem/functions/basisgridfunction.hh> #include <dune/fufem/functions/constantfunction.hh> #include <dune/fufem/quadraturerules/quadraturerulecache.hh> #include <dune/tectonic/frictionpotential.hh> #include <dune/tectonic/globalratestatefriction.hh> +#include <dune/tectonic/pointtractionboundaryassembler.hh> #include "assemblers.hh" @@ -104,21 +104,27 @@ void MyAssembler<GridView, dimension>::assembleNeumann( } template <class GridView, int dimension> -void MyAssembler<GridView, dimension>::assembleNormalStress( +void MyAssembler<GridView, dimension>::assembleWeightedNormalStress( BoundaryPatch<GridView> const &frictionalBoundary, - ScalarVector &normalStress, double youngModulus, double poissonRatio, - Vector const &displacement) const { + ScalarVector &weightedNormalStress, double youngModulus, + double poissonRatio, Vector const &displacement) const { + BasisGridFunction<VertexBasis, Vector> displacementFunction(vertexBasis, + displacement); Vector traction; - Stress<GridView>::getElasticSurfaceNormalStress // misnomer(!) - (frictionalBoundary, displacement, traction, youngModulus, poissonRatio); + // Note: We assume v = 0 here so that there is no viscous + // contribution to the stress. + PointTractionBoundaryAssembler<Grid> weightedNormalStressBoundaryAssembler( + youngModulus, poissonRatio, &displacementFunction, 1); + vertexAssembler.assembleBoundaryFunctional( + weightedNormalStressBoundaryAssembler, traction, frictionalBoundary); std::vector<typename Vector::block_type> normals; frictionalBoundary.getNormals(normals); for (size_t i = 0; i < traction.size(); ++i) { - normalStress[i] = normals[i] * traction[i]; - if (normalStress[i] > 0.0) { - normalStress[i] = 0.0; + weightedNormalStress[i] = normals[i] * traction[i]; + if (weightedNormalStress[i] > 0.0) { + weightedNormalStress[i] = 0.0; std::cout << "Warning: Manually reducing positive normal stress to zero." << std::endl; } @@ -130,9 +136,9 @@ auto MyAssembler<GridView, dimension>::assembleFrictionNonlinearity( Config::FrictionModel frictionModel, BoundaryPatch<GridView> const &frictionalBoundary, GlobalFrictionData<dimension> const &frictionInfo, - ScalarVector const &normalStress) const + ScalarVector const &weightedNormalStress) const -> std::shared_ptr<GlobalFriction<Matrix, Vector>> { - // Lump negative normal stress (kludge) + // Lumping of the nonlinearity ScalarVector weights; { NeumannBoundaryAssembler<Grid, typename ScalarVector::block_type> @@ -142,10 +148,6 @@ auto MyAssembler<GridView, dimension>::assembleFrictionNonlinearity( vertexAssembler.assembleBoundaryFunctional(frictionalBoundaryAssembler, weights, frictionalBoundary); } - ScalarVector weightedNormalStress(weights.size()); - for (size_t i = 0; i < weights.size(); ++i) - weightedNormalStress[i] = weights[i] * normalStress[i]; - switch (frictionModel) { case Config::Truncated: return std::make_shared<GlobalRateStateFriction< diff --git a/src/assemblers.hh b/src/assemblers.hh index 9fd600fb..b3227a9a 100644 --- a/src/assemblers.hh +++ b/src/assemblers.hh @@ -73,16 +73,16 @@ template <class GridView, int dimension> class MyAssembler { Dune::VirtualFunction<double, double> const &neumann, double relativeTime) const; - void assembleNormalStress(BoundaryPatch<GridView> const &frictionalBoundary, - ScalarVector &normalStress, double youngModulus, - double poissonRatio, - Vector const &displacement) const; + void assembleWeightedNormalStress( + BoundaryPatch<GridView> const &frictionalBoundary, + ScalarVector &weightedNormalStress, double youngModulus, + double poissonRatio, Vector const &displacement) const; std::shared_ptr<GlobalFriction<Matrix, Vector>> assembleFrictionNonlinearity( Config::FrictionModel frictionModel, BoundaryPatch<GridView> const &frictionalBoundary, GlobalFrictionData<dimension> const &frictionInfo, - ScalarVector const &normalStress) const; + ScalarVector const &weightedNormalStress) const; void assembleVonMisesStress(double youngModulus, double poissonRatio, Vector const &u, ScalarVector &stress) const; diff --git a/src/program_state.hh b/src/program_state.hh index 6ce0eba0..0c544041 100644 --- a/src/program_state.hh +++ b/src/program_state.hh @@ -19,7 +19,7 @@ template <class Vector, class ScalarVector> class ProgramState { v(leafVertexCount), a(leafVertexCount), alpha(leafVertexCount), - normalStress(leafVertexCount) {} + weightedNormalStress(leafVertexCount) {} // Set up initial conditions template <class Matrix, class GridView> @@ -96,9 +96,9 @@ template <class Vector, class ScalarVector> class ProgramState { alpha = parset.get<double>("boundary.friction.initialAlpha"); // Initial normal stress - myAssembler.assembleNormalStress(frictionalBoundary, normalStress, - body.getYoungModulus(), - body.getPoissonRatio(), u); + myAssembler.assembleWeightedNormalStress( + frictionalBoundary, weightedNormalStress, body.getYoungModulus(), + body.getPoissonRatio(), u); } public: @@ -106,7 +106,7 @@ template <class Vector, class ScalarVector> class ProgramState { Vector v; Vector a; ScalarVector alpha; - ScalarVector normalStress; + ScalarVector weightedNormalStress; double relativeTime; double relativeTau; size_t timeStep; @@ -121,7 +121,7 @@ namespace serialization { ar &ps.v; ar &ps.a; ar &ps.alpha; - ar &ps.normalStress; + ar &ps.weightedNormalStress; ar &ps.relativeTime; ar &ps.relativeTau; ar &ps.timeStep; diff --git a/src/sand-wedge.cc b/src/sand-wedge.cc index e4baf5b5..c8795737 100644 --- a/src/sand-wedge.cc +++ b/src/sand-wedge.cc @@ -225,7 +225,7 @@ int main(int argc, char *argv[]) { parset.sub("boundary.friction"), weakPatch); auto myGlobalFriction = myAssembler.assembleFrictionNonlinearity( parset.get<Config::FrictionModel>("boundary.friction.frictionModel"), - frictionalBoundary, frictionInfo, programState.normalStress); + frictionalBoundary, frictionInfo, programState.weightedNormalStress); myGlobalFriction->updateAlpha(programState.alpha); Vector vertexCoordinates(leafVertexCount); -- GitLab