From c0bfa724e0d70f10b135a3491d1aa1c91224cb25 Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@igpm.rwth-aachen.de> Date: Thu, 13 Jan 2011 10:57:33 +0000 Subject: [PATCH] Moved the Richardson iteration with a Steklov-Poincare preconditioner into a separate file [[Imported from SVN: r6736]] --- dirneucoupling.cc | 393 +------------ .../rodcontinuumsteklovpoincarestep.hh | 519 ++++++++++++++++++ 2 files changed, 536 insertions(+), 376 deletions(-) create mode 100644 dune/gfe/coupling/rodcontinuumsteklovpoincarestep.hh diff --git a/dirneucoupling.cc b/dirneucoupling.cc index cf0b703e..41fc5e98 100644 --- a/dirneucoupling.cc +++ b/dirneucoupling.cc @@ -39,6 +39,7 @@ #include <dune/gfe/rodwriter.hh> #include <dune/gfe/makestraightrod.hh> #include <dune/gfe/coupling/rodcontinuumcomplex.hh> +#include <dune/gfe/coupling/rodcontinuumsteklovpoincarestep.hh> // Space dimension const int dim = 3; @@ -53,229 +54,6 @@ using std::vector; typedef vector<RigidBodyMotion<dim> > RodSolutionType; typedef BlockVector<FieldVector<double, 6> > RodDifferenceType; -template <class GridView, class MatrixType, class VectorType> -class LinearizedContinuumNeumannToDirichletMap -{ -public: - - /** \brief Constructor - * - */ - LinearizedContinuumNeumannToDirichletMap(const BoundaryPatchBase<GridView>& interface, - const VectorType& weakVolumeAndNeumannTerm, - const VectorType& dirichletValues, - const LinearLocalAssembler<typename GridView::Grid, - typename P1NodalBasis<GridView,double>::LocalFiniteElement, - typename P1NodalBasis<GridView,double>::LocalFiniteElement, - Dune::FieldMatrix<double,3,3> >* localAssembler, - const shared_ptr< ::LoopSolver<VectorType> >& solver - ) - : interface_(interface), - weakVolumeAndNeumannTerm_(weakVolumeAndNeumannTerm), - dirichletValues_(dirichletValues), - solver_(solver), - localAssembler_(localAssembler) - {} - - /** \brief Map a Neumann value to a Dirichlet value - * - * \param currentIterate The continuum configuration that we are linearizing about - * - * \return The infinitesimal movement of the interface - */ - FieldVector<double,6> apply(const VectorType& currentIterate, - const Dune::FieldVector<double,3>& force, - const Dune::FieldVector<double,3>& torque, - const Dune::FieldVector<double,3>& centerOfTorque - ) - { - //////////////////////////////////////////////////// - // Assemble the linearized problem - //////////////////////////////////////////////////// - - /** \todo We are actually assembling standard linear elasticity, - * i.e. the linearization at zero - */ - typedef P1NodalBasis<GridView,double> P1Basis; - P1Basis basis(interface_.gridView()); - OperatorAssembler<P1Basis,P1Basis> assembler(basis, basis); - - MatrixType stiffnessMatrix; - assembler.assemble(*localAssembler_, stiffnessMatrix); - - - ///////////////////////////////////////////////////////////////////// - // Turn the input force and torque into a Neumann boundary field - ///////////////////////////////////////////////////////////////////// - VectorType neumannValues(stiffnessMatrix.N()); - neumannValues = 0; - - // - computeAveragePressure<GridView>(force, torque, - interface_, - centerOfTorque, - neumannValues); - - // The weak form of the Neumann data - VectorType rhs = weakVolumeAndNeumannTerm_; - assembleAndAddNeumannTerm<GridView, VectorType>(interface_, - neumannValues, - rhs); - - // Solve the Neumann problem for the continuum - VectorType x = dirichletValues_; - assert( (dynamic_cast<LinearIterationStep<MatrixType,VectorType>* >(solver_->iterationStep_)) ); - dynamic_cast<LinearIterationStep<MatrixType,VectorType>* >(solver_->iterationStep_)->setProblem(stiffnessMatrix, x, rhs); - - //solver.preprocess(); - solver_->iterationStep_->preprocess(); - - solver_->solve(); - - x = solver_->iterationStep_->getSol(); - - std::cout << "x:\n" << x << std::endl; - - // Average the continuum displacement on the coupling boundary - RigidBodyMotion<3> averageInterface; - computeAverageInterface(interface_, x, averageInterface); - - std::cout << "Average interface: " << averageInterface << std::endl; - - // Compute the linearization - FieldVector<double,6> interfaceCorrection; - interfaceCorrection[0] = averageInterface.r[0]; - interfaceCorrection[1] = averageInterface.r[1]; - interfaceCorrection[2] = averageInterface.r[2]; - - FieldVector<double,3> infinitesimalRotation = Rotation<3,double>::expInv(averageInterface.q); - interfaceCorrection[3] = infinitesimalRotation[0]; - interfaceCorrection[4] = infinitesimalRotation[1]; - interfaceCorrection[5] = infinitesimalRotation[2]; - - return interfaceCorrection; - } - -private: - - const VectorType& weakVolumeAndNeumannTerm_; - - const VectorType& dirichletValues_; - - const shared_ptr< ::LoopSolver<VectorType> > solver_; - - const BoundaryPatchBase<GridView>& interface_; - - const LinearLocalAssembler<typename GridView::Grid, - typename P1NodalBasis<GridView,double>::LocalFiniteElement, - typename P1NodalBasis<GridView,double>::LocalFiniteElement, - Dune::FieldMatrix<double,3,3> >* localAssembler_; -}; - - -template <class GridView, class VectorType> -class LinearizedRodNeumannToDirichletMap -{ -public: - - /** \brief Constructor - * - */ - LinearizedRodNeumannToDirichletMap(const BoundaryPatchBase<GridView>& interface, - LocalGeodesicFEStiffness<GridView, RigidBodyMotion<3> >* localAssembler) - : interface_(interface), - localAssembler_(localAssembler) - {} - - /** \brief Map a Neumann value to a Dirichlet value - * - * \param currentIterate The rod configuration that we are linearizing about - * - * \return The Dirichlet value - */ - Dune::FieldVector<double,6> apply(const RodSolutionType& currentIterate, - const Dune::FieldVector<double,3>& force, - const Dune::FieldVector<double,3>& torque, - const Dune::FieldVector<double,3>& centerOfTorque - ) - { - //////////////////////////////////////////////////// - // Assemble the linearized rod problem - //////////////////////////////////////////////////// - - typedef BCRSMatrix<FieldMatrix<double,6,6> > MatrixType; - GeodesicFEAssembler<GridView, RigidBodyMotion<3> > assembler(interface_.gridView(), - localAssembler_); - MatrixType stiffnessMatrix; - assembler.assembleMatrix(currentIterate, - stiffnessMatrix, - true // assemble occupation pattern - ); - - VectorType rhs(currentIterate.size()); - rhs = 0; - assembler.assembleGradient(currentIterate, rhs); - - // The right hand side is the _negative_ gradient - rhs *= -1; - - ///////////////////////////////////////////////////////////////////// - // Turn the input force and torque into a Neumann boundary field - ///////////////////////////////////////////////////////////////////// - - // The weak form of the Neumann data - rhs[0][0] += force[0]; - rhs[0][1] += force[1]; - rhs[0][2] += force[2]; - rhs[0][3] += torque[0]; - rhs[0][4] += torque[1]; - rhs[0][5] += torque[2]; - - /////////////////////////////////////////////////////////// - // Modify matrix and rhs to contain one Dirichlet node - /////////////////////////////////////////////////////////// - - int dIdx = rhs.size()-1; // hardwired index of the single Dirichlet node - rhs[dIdx] = 0; - stiffnessMatrix[dIdx] = 0; - stiffnessMatrix[dIdx][dIdx] = Dune::ScaledIdentityMatrix<double,6>(1); - - ////////////////////////////////////////////////// - // Solve the Neumann problem - ////////////////////////////////////////////////// - - VectorType x(rhs.size()); - x = 0; // initial iterate - - // Technicality: turn the matrix into a linear operator - Dune::MatrixAdapter<MatrixType,VectorType,VectorType> op(stiffnessMatrix); - - // A preconditioner - Dune::SeqILU0<MatrixType,VectorType,VectorType> ilu0(stiffnessMatrix,1.0); - - // A preconditioned conjugate-gradient solver - Dune::CGSolver<VectorType> cg(op,ilu0,1E-4,100,2); - - // Object storing some statistics about the solving process - Dune::InverseOperatorResult statistics; - - // Solve! - cg.apply(x, rhs, statistics); - - std::cout << "x:\n" << x << std::endl; - - std::cout << "Linear rod interface correction: " << x[0] << std::endl; - - return x[0]; - } - -private: - - const BoundaryPatchBase<GridView>& interface_; - - LocalGeodesicFEStiffness<GridView, RigidBodyMotion<3> >* localAssembler_; -}; - int main (int argc, char *argv[]) try { @@ -514,7 +292,7 @@ int main (int argc, char *argv[]) try // Make pre and postsmoothers BlockGSStep<MatrixType, VectorType> presmoother, postsmoother; - MultigridStep<MatrixType, VectorType> multigridStep(stiffnessMatrix3d, x3d, rhs3d, 1); + MultigridStep<MatrixType, VectorType> multigridStep(stiffnessMatrix3d, x3d, rhs3d, toplevel+1); multigridStep.setMGType(mu, nu1, nu2); multigridStep.ignoreNodes_ = &dirichletNodes.back(); @@ -660,160 +438,23 @@ int main (int argc, char *argv[]) try } else if (ddType=="RichardsonIteration") { - /////////////////////////////////////////////////////////////////// - // One preconditioned Richardson step - /////////////////////////////////////////////////////////////////// - - /////////////////////////////////////////////////////////////////// - // Evaluate the Dirichlet-to-Neumann map for the rod - /////////////////////////////////////////////////////////////////// - - // solve a Dirichlet problem for the rod - rodX[0] = lambda; - rodSolver.setInitialSolution(rodX); - rodSolver.solve(); - - rodX = rodSolver.getSol(); - - // Extract Neumann values - - BitSetVector<1> couplingBitfield(rodX.size(),false); - // Using that index 0 is always the left boundary for a uniformly refined OneDGrid - couplingBitfield[0] = true; - LeafBoundaryPatch<RodGridType> couplingBoundary(*complex.rodGrids_["rod"], couplingBitfield); - - FieldVector<double,dim> resultantForce, resultantTorque; - resultantForce = rodAssembler.getResultantForce(couplingBoundary, rodX, resultantTorque); - - // Flip orientation - resultantForce *= -1; - resultantTorque *= -1; - - std::cout << "resultant force: " << resultantForce << std::endl; - std::cout << "resultant torque: " << resultantTorque << std::endl; - - /////////////////////////////////////////////////////////////////// - // Evaluate the Dirichlet-to-Neumann map for the continuum - /////////////////////////////////////////////////////////////////// - - // Turn \lambda \in TSE(3) into a Dirichlet value for the continuum - RigidBodyMotion<3> relativeMovement; - relativeMovement.r = lambda.r - referenceInterface.r; - relativeMovement.q = referenceInterface.q; - relativeMovement.q.invert(); - relativeMovement.q = lambda.q.mult(relativeMovement.q); - - setRotation(interfaceBoundary.back(), x3d, relativeMovement); - - // Solve the Dirichlet problem - multigridStep.setProblem(stiffnessMatrix3d, x3d, rhs3d, complex.continuumGrids_["continuum"]->maxLevel()+1); - - solver->preprocess(); - multigridStep.preprocess(); - - solver->solve(); - - x3d = multigridStep.getSol(); - - // Integrate over the residual on the coupling boundary to obtain - // an element of T^*SE. - FieldVector<double,3> continuumForce, continuumTorque; - - VectorType residual = rhs3d; - stiffnessMatrix3d.mmv(x3d,residual); - - /** \todo Is referenceInterface.r the correct center of rotation? */ - computeTotalForceAndTorque(interfaceBoundary.back(), residual, referenceInterface.r, - continuumForce, continuumTorque); - - /////////////////////////////////////////////////////////////// - // Compute the overall Steklov-Poincare residual - /////////////////////////////////////////////////////////////// - - FieldVector<double,3> residualForce = resultantForce + continuumForce; - FieldVector<double,3> residualTorque = resultantTorque + continuumTorque; - - - - /////////////////////////////////////////////////////////////// - // Apply the preconditioner - /////////////////////////////////////////////////////////////// - - FieldVector<double,6> interfaceCorrection; - - if (preconditioner=="DirichletNeumann") { - - //////////////////////////////////////////////////////////////////// - // Preconditioner is the linearized Neumann-to-Dirichlet map - // of the continuum. - //////////////////////////////////////////////////////////////////// - - LinearizedContinuumNeumannToDirichletMap<GridType::LevelGridView,MatrixType,VectorType> - linContNtDMap(interfaceBoundary.back(), - rhs3d, - dirichletValues.back(), - &localAssembler, - solver); - - interfaceCorrection = linContNtDMap.apply(x3d, residualForce, residualTorque, rodX[0].r); - - } else if (preconditioner=="NeumannDirichlet") { - - //////////////////////////////////////////////////////////////////// - // Preconditioner is the linearized Neumann-to-Dirichlet map - // of the rod. - //////////////////////////////////////////////////////////////////// - - typedef BlockVector<FieldVector<double,6> > RodVectorType; - - LinearizedRodNeumannToDirichletMap<RodGridType::LeafGridView,RodVectorType> linRodNtDMap(couplingBoundary, - &rodLocalStiffness); - - interfaceCorrection = linRodNtDMap.apply(rodX, residualForce, residualTorque, rodX[0].r); - - - } else if (preconditioner=="NeumannNeumann") { - - //////////////////////////////////////////////////////////////////// - // Preconditioner is a convex combination of the linearized - // Neumann-to-Dirichlet map of the continuum and the linearized - // Neumann-to-Dirichlet map of the rod. - //////////////////////////////////////////////////////////////////// - - LinearizedContinuumNeumannToDirichletMap<GridType::LevelGridView,MatrixType,VectorType> - linContNtDMap(interfaceBoundary.back(), - rhs3d, - dirichletValues.back(), - &localAssembler, - solver); - - typedef BlockVector<FieldVector<double,6> > RodVectorType; - - LinearizedRodNeumannToDirichletMap<RodGridType::LeafGridView,RodVectorType> linRodNtDMap(couplingBoundary, - &rodLocalStiffness); - - array<double, 2> alpha = parameterSet.get<array<double,2> >("neumannNeumannWeights"); - - FieldVector<double,6> continuumCorrection = linContNtDMap.apply(x3d, residualForce, residualTorque, rodX[0].r); - FieldVector<double,6> rodCorrection = linRodNtDMap.apply(rodX, residualForce, residualTorque, rodX[0].r); - - for (int j=0; j<6; j++) - interfaceCorrection[j] = (alpha[0] * continuumCorrection[j] + alpha[1] * rodCorrection[j]) - / alpha[0] + alpha[1]; - - } else if (preconditioner=="RobinRobin") { + Dune::array<double,2> alpha = parameterSet.get<array<double,2> >("NeumannNeumannDamping"); - DUNE_THROW(NotImplemented, "Robin-Robin preconditioner not implemented yet"); - - } else - DUNE_THROW(NotImplemented, preconditioner << " is not a known preconditioner"); + RodContinuumSteklovPoincareStep<RodGridType,GridType> rodContinuumSteklovPoincareStep(complex, + preconditioner, + alpha, + damping, + referenceInterface, + &rodAssembler, + &rodLocalStiffness, + &rodSolver, + &interfaceBoundary.back(), + &stiffnessMatrix3d, + &dirichletValues.back(), + solver, + &localAssembler); - /////////////////////////////////////////////////////////////////////////////// - // Apply the damped correction to the current interface value - /////////////////////////////////////////////////////////////////////////////// - - interfaceCorrection *= damping; - lambda = RigidBodyMotion<3>::exp(lambda, interfaceCorrection); + rodContinuumSteklovPoincareStep.iterate(lambda); } else DUNE_THROW(NotImplemented, ddType << " is not a known domain decomposition algorithm"); diff --git a/dune/gfe/coupling/rodcontinuumsteklovpoincarestep.hh b/dune/gfe/coupling/rodcontinuumsteklovpoincarestep.hh new file mode 100644 index 00000000..7d0d95f7 --- /dev/null +++ b/dune/gfe/coupling/rodcontinuumsteklovpoincarestep.hh @@ -0,0 +1,519 @@ +#ifndef ROD_CONTINUUM_STEKLOV_POINCARE_STEP_HH +#define ROD_CONTINUUM_STEKLOV_POINCARE_STEP_HH + +#include <vector> + +#include <dune/common/shared_ptr.hh> +#include <dune/common/fvector.hh> +#include <dune/common/fmatrix.hh> +#include <dune/common/bitsetvector.hh> + +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/bvector.hh> + +#include <dune/gfe/coupling/rodcontinuumcomplex.hh> + +template <class GridView, class MatrixType, class VectorType> +class LinearizedContinuumNeumannToDirichletMap +{ +public: + + /** \brief Constructor + * + */ + LinearizedContinuumNeumannToDirichletMap(const BoundaryPatchBase<GridView>& interface, + const VectorType& weakVolumeAndNeumannTerm, + const VectorType& dirichletValues, + const LinearLocalAssembler<typename GridView::Grid, + typename P1NodalBasis<GridView,double>::LocalFiniteElement, + typename P1NodalBasis<GridView,double>::LocalFiniteElement, + Dune::FieldMatrix<double,3,3> >* localAssembler, + const Dune::shared_ptr< ::LoopSolver<VectorType> >& solver + ) + : interface_(interface), + weakVolumeAndNeumannTerm_(weakVolumeAndNeumannTerm), + dirichletValues_(dirichletValues), + solver_(solver), + localAssembler_(localAssembler) + {} + + /** \brief Map a Neumann value to a Dirichlet value + * + * \param currentIterate The continuum configuration that we are linearizing about + * + * \return The infinitesimal movement of the interface + */ + Dune::FieldVector<double,6> apply(const VectorType& currentIterate, + const Dune::FieldVector<double,3>& force, + const Dune::FieldVector<double,3>& torque, + const Dune::FieldVector<double,3>& centerOfTorque + ) + { + //////////////////////////////////////////////////// + // Assemble the linearized problem + //////////////////////////////////////////////////// + + /** \todo We are actually assembling standard linear elasticity, + * i.e. the linearization at zero + */ + typedef P1NodalBasis<GridView,double> P1Basis; + P1Basis basis(interface_.gridView()); + OperatorAssembler<P1Basis,P1Basis> assembler(basis, basis); + + MatrixType stiffnessMatrix; + assembler.assemble(*localAssembler_, stiffnessMatrix); + + + ///////////////////////////////////////////////////////////////////// + // Turn the input force and torque into a Neumann boundary field + ///////////////////////////////////////////////////////////////////// + VectorType neumannValues(stiffnessMatrix.N()); + neumannValues = 0; + + // + computeAveragePressure<GridView>(force, torque, + interface_, + centerOfTorque, + neumannValues); + + // The weak form of the Neumann data + VectorType rhs = weakVolumeAndNeumannTerm_; + assembleAndAddNeumannTerm<GridView, VectorType>(interface_, + neumannValues, + rhs); + + // Solve the Neumann problem for the continuum + VectorType x = dirichletValues_; + assert( (dynamic_cast<LinearIterationStep<MatrixType,VectorType>* >(solver_->iterationStep_)) ); + dynamic_cast<LinearIterationStep<MatrixType,VectorType>* >(solver_->iterationStep_)->setProblem(stiffnessMatrix, x, rhs); + + //solver.preprocess(); + solver_->iterationStep_->preprocess(); + + solver_->solve(); + + x = solver_->iterationStep_->getSol(); + + std::cout << "x:\n" << x << std::endl; + + // Average the continuum displacement on the coupling boundary + RigidBodyMotion<3> averageInterface; + computeAverageInterface(interface_, x, averageInterface); + + std::cout << "Average interface: " << averageInterface << std::endl; + + // Compute the linearization + Dune::FieldVector<double,6> interfaceCorrection; + interfaceCorrection[0] = averageInterface.r[0]; + interfaceCorrection[1] = averageInterface.r[1]; + interfaceCorrection[2] = averageInterface.r[2]; + + Dune::FieldVector<double,3> infinitesimalRotation = Rotation<3,double>::expInv(averageInterface.q); + interfaceCorrection[3] = infinitesimalRotation[0]; + interfaceCorrection[4] = infinitesimalRotation[1]; + interfaceCorrection[5] = infinitesimalRotation[2]; + + return interfaceCorrection; + } + +private: + + const VectorType& weakVolumeAndNeumannTerm_; + + const VectorType& dirichletValues_; + + const Dune::shared_ptr< ::LoopSolver<VectorType> > solver_; + + const BoundaryPatchBase<GridView>& interface_; + + const LinearLocalAssembler<typename GridView::Grid, + typename P1NodalBasis<GridView,double>::LocalFiniteElement, + typename P1NodalBasis<GridView,double>::LocalFiniteElement, + Dune::FieldMatrix<double,3,3> >* localAssembler_; +}; + + +template <class GridView, class VectorType> +class LinearizedRodNeumannToDirichletMap +{ + static const int dim = 3; + + typedef std::vector<RigidBodyMotion<dim> > RodSolutionType; + +public: + + /** \brief Constructor + * + */ + LinearizedRodNeumannToDirichletMap(const BoundaryPatchBase<GridView>& interface, + LocalGeodesicFEStiffness<GridView, RigidBodyMotion<3> >* localAssembler) + : interface_(interface), + localAssembler_(localAssembler) + {} + + /** \brief Map a Neumann value to a Dirichlet value + * + * \param currentIterate The rod configuration that we are linearizing about + * + * \return The Dirichlet value + */ + Dune::FieldVector<double,6> apply(const RodSolutionType& currentIterate, + const Dune::FieldVector<double,3>& force, + const Dune::FieldVector<double,3>& torque, + const Dune::FieldVector<double,3>& centerOfTorque + ) + { + //////////////////////////////////////////////////// + // Assemble the linearized rod problem + //////////////////////////////////////////////////// + + typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,6,6> > MatrixType; + GeodesicFEAssembler<GridView, RigidBodyMotion<3> > assembler(interface_.gridView(), + localAssembler_); + MatrixType stiffnessMatrix; + assembler.assembleMatrix(currentIterate, + stiffnessMatrix, + true // assemble occupation pattern + ); + + VectorType rhs(currentIterate.size()); + rhs = 0; + assembler.assembleGradient(currentIterate, rhs); + + // The right hand side is the _negative_ gradient + rhs *= -1; + + ///////////////////////////////////////////////////////////////////// + // Turn the input force and torque into a Neumann boundary field + ///////////////////////////////////////////////////////////////////// + + // The weak form of the Neumann data + rhs[0][0] += force[0]; + rhs[0][1] += force[1]; + rhs[0][2] += force[2]; + rhs[0][3] += torque[0]; + rhs[0][4] += torque[1]; + rhs[0][5] += torque[2]; + + /////////////////////////////////////////////////////////// + // Modify matrix and rhs to contain one Dirichlet node + /////////////////////////////////////////////////////////// + + int dIdx = rhs.size()-1; // hardwired index of the single Dirichlet node + rhs[dIdx] = 0; + stiffnessMatrix[dIdx] = 0; + stiffnessMatrix[dIdx][dIdx] = Dune::ScaledIdentityMatrix<double,6>(1); + + ////////////////////////////////////////////////// + // Solve the Neumann problem + ////////////////////////////////////////////////// + + VectorType x(rhs.size()); + x = 0; // initial iterate + + // Technicality: turn the matrix into a linear operator + Dune::MatrixAdapter<MatrixType,VectorType,VectorType> op(stiffnessMatrix); + + // A preconditioner + Dune::SeqILU0<MatrixType,VectorType,VectorType> ilu0(stiffnessMatrix,1.0); + + // A preconditioned conjugate-gradient solver + Dune::CGSolver<VectorType> cg(op,ilu0,1E-4,100,2); + + // Object storing some statistics about the solving process + Dune::InverseOperatorResult statistics; + + // Solve! + cg.apply(x, rhs, statistics); + + std::cout << "x:\n" << x << std::endl; + + std::cout << "Linear rod interface correction: " << x[0] << std::endl; + + return x[0]; + } + +private: + + const BoundaryPatchBase<GridView>& interface_; + + LocalGeodesicFEStiffness<GridView, RigidBodyMotion<3> >* localAssembler_; +}; + + +template <class RodGridType, class ContinuumGridType> +class RodContinuumSteklovPoincareStep +{ + static const int dim = ContinuumGridType::dimension; + + // The type used for rod configurations + typedef std::vector<RigidBodyMotion<dim> > RodSolutionType; + + // The type used for continuum configurations + typedef Dune::BlockVector<Dune::FieldVector<double,dim> > VectorType; + + typedef Dune::BlockVector<Dune::FieldVector<double,6> > RodCorrectionType; + + typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,3,3> > MatrixType; + + typedef P1NodalBasis<typename ContinuumGridType::LeafGridView,double> ContinuumFEBasis; + +public: + + /** \brief Constructor */ + RodContinuumSteklovPoincareStep(const RodContinuumComplex<RodGridType,ContinuumGridType>& complex, + const std::string& preconditioner, + const Dune::array<double,2>& alpha, + double richardsonDamping, + const RigidBodyMotion<3>& referenceInterface, + RodAssembler<typename RodGridType::LeafGridView,3>* rodAssembler, + RodLocalStiffness<typename RodGridType::LeafGridView,double>* rodLocalStiffness, + RiemannianTrustRegionSolver<RodGridType,RigidBodyMotion<3> >* rodSolver, + const LevelBoundaryPatch<ContinuumGridType>* interfaceBoundary, + const MatrixType* stiffnessMatrix3d, + const VectorType* dirichletValues, + const Dune::shared_ptr< ::LoopSolver<VectorType> > solver, + StVenantKirchhoffAssembler<ContinuumGridType, + typename ContinuumFEBasis::LocalFiniteElement, + typename ContinuumFEBasis::LocalFiniteElement>* localAssembler) + : complex_(complex), + preconditioner_(preconditioner), + alpha_(alpha), + richardsonDamping_(richardsonDamping), + referenceInterface_(referenceInterface), + rodAssembler_(rodAssembler), + rodLocalStiffness_(rodLocalStiffness), + rodSolver_(rodSolver), + interfaceBoundary_(interfaceBoundary), + stiffnessMatrix3d_(stiffnessMatrix3d), + dirichletValues_(dirichletValues), + solver_(solver), + localAssembler_(localAssembler) + {} + + + + + + + + + + /** \brief Do one Steklov-Poincare step + * \param[in,out] lambda The old and new iterate + */ + void iterate(RigidBodyMotion<3>& lambda); + +private: + + ////////////////////////////////////////////////////////////////// + // Data members related to the coupled problem + ////////////////////////////////////////////////////////////////// + RodContinuumComplex<RodGridType,ContinuumGridType> complex_; + + std::string preconditioner_; + + /** \brief Neumann-Neumann damping */ + Dune::array<double,2> alpha_; + + double richardsonDamping_; + + ////////////////////////////////////////////////////////////////// + // Data members related to the rod problems + ////////////////////////////////////////////////////////////////// + RigidBodyMotion<dim> referenceInterface_; + + RodAssembler<typename RodGridType::LeafGridView,3>* rodAssembler_; + + RodLocalStiffness<typename RodGridType::LeafGridView,double>* rodLocalStiffness_; + + RiemannianTrustRegionSolver<RodGridType,RigidBodyMotion<3> >* rodSolver_; + + ////////////////////////////////////////////////////////////////// + // Data members related to the continuum problems + ////////////////////////////////////////////////////////////////// + + const LevelBoundaryPatch<ContinuumGridType>* interfaceBoundary_; + + const MatrixType* stiffnessMatrix3d_; + + const VectorType* dirichletValues_; + + const Dune::shared_ptr< ::LoopSolver<VectorType> > solver_; + + /** \todo Hack: + * - we actually need a base class + * - we don't need the global ContinuumFEBasis + */ + StVenantKirchhoffAssembler<ContinuumGridType, + typename ContinuumFEBasis::LocalFiniteElement, + typename ContinuumFEBasis::LocalFiniteElement>* localAssembler_; + +}; + + +/** \brief One preconditioned Richardson step +*/ +template <class RodGridType, class ContinuumGridType> +void RodContinuumSteklovPoincareStep<RodGridType,ContinuumGridType>::iterate(RigidBodyMotion<3>& lambda) +{ + /////////////////////////////////////////////////////////////////// + // Evaluate the Dirichlet-to-Neumann map for the rod + /////////////////////////////////////////////////////////////////// + + // solve a Dirichlet problem for the rod + RodSolutionType rodX; + /** \todo Using that index 0 is always the left boundary for a uniformly refined OneDGrid */ + rodX[0] = lambda; +#warning Dirichlet boundary not properly set + rodX.back() = lambda; + rodSolver_->setInitialSolution(rodX); + rodSolver_->solve(); + + rodX = rodSolver_->getSol(); + + // Extract Neumann values + + Dune::BitSetVector<1> couplingBitfield(rodX.size(),false); + /** \todo Using that index 0 is always the left boundary for a uniformly refined OneDGrid */ + couplingBitfield[0] = true; + LeafBoundaryPatch<RodGridType> couplingBoundary(*complex_.rodGrids_["rod"], couplingBitfield); + + Dune::FieldVector<double,dim> resultantForce, resultantTorque; + resultantForce = rodAssembler_->getResultantForce(couplingBoundary, rodX, resultantTorque); + + // Flip orientation + resultantForce *= -1; + resultantTorque *= -1; + + std::cout << "resultant force: " << resultantForce << std::endl; + std::cout << "resultant torque: " << resultantTorque << std::endl; + + /////////////////////////////////////////////////////////////////// + // Evaluate the Dirichlet-to-Neumann map for the continuum + /////////////////////////////////////////////////////////////////// + + VectorType x3d(complex_.continuumGrids_["continuum"]->size(dim)); + x3d = 0; + + // Turn \lambda \in TSE(3) into a Dirichlet value for the continuum + RigidBodyMotion<3> relativeMovement; + relativeMovement.r = lambda.r - referenceInterface_.r; + relativeMovement.q = referenceInterface_.q; + relativeMovement.q.invert(); + relativeMovement.q = lambda.q.mult(relativeMovement.q); + + setRotation(*interfaceBoundary_, x3d, relativeMovement); + + // Right hand side vector: currently with Neumann and volume terms + VectorType rhs3d(x3d.size()); + rhs3d = 0; + + // Solve the Dirichlet problem + assert( (dynamic_cast<LinearIterationStep<MatrixType,VectorType>* >(solver_->iterationStep_)) ); + dynamic_cast<LinearIterationStep<MatrixType,VectorType>* >(solver_->iterationStep_)->setProblem(*stiffnessMatrix3d_, x3d, rhs3d); + + solver_->preprocess(); + dynamic_cast<IterationStep<VectorType>* >(solver_->iterationStep_)->preprocess(); + + solver_->solve(); + + x3d = dynamic_cast<IterationStep<VectorType>* >(solver_->iterationStep_)->getSol(); + + // Integrate over the residual on the coupling boundary to obtain + // an element of T^*SE. + Dune::FieldVector<double,3> continuumForce, continuumTorque; + + VectorType residual = rhs3d; + stiffnessMatrix3d_->mmv(x3d,residual); + + /** \todo Is referenceInterface.r the correct center of rotation? */ + computeTotalForceAndTorque(*interfaceBoundary_, residual, referenceInterface_.r, + continuumForce, continuumTorque); + + /////////////////////////////////////////////////////////////// + // Compute the overall Steklov-Poincare residual + /////////////////////////////////////////////////////////////// + + Dune::FieldVector<double,3> residualForce = resultantForce + continuumForce; + Dune::FieldVector<double,3> residualTorque = resultantTorque + continuumTorque; + + + + /////////////////////////////////////////////////////////////// + // Apply the preconditioner + /////////////////////////////////////////////////////////////// + + Dune::FieldVector<double,6> interfaceCorrection; + + if (preconditioner_=="DirichletNeumann") { + + //////////////////////////////////////////////////////////////////// + // Preconditioner is the linearized Neumann-to-Dirichlet map + // of the continuum. + //////////////////////////////////////////////////////////////////// + + LinearizedContinuumNeumannToDirichletMap<typename ContinuumGridType::LevelGridView,MatrixType,VectorType> + linContNtDMap(*interfaceBoundary_, + rhs3d, + *dirichletValues_, + localAssembler_, + solver_); + + interfaceCorrection = linContNtDMap.apply(x3d, residualForce, residualTorque, rodX[0].r); + + } else if (preconditioner_=="NeumannDirichlet") { + + //////////////////////////////////////////////////////////////////// + // Preconditioner is the linearized Neumann-to-Dirichlet map + // of the rod. + //////////////////////////////////////////////////////////////////// + + LinearizedRodNeumannToDirichletMap<typename RodGridType::LeafGridView,RodCorrectionType> linRodNtDMap(couplingBoundary, + rodLocalStiffness_); + + interfaceCorrection = linRodNtDMap.apply(rodX, residualForce, residualTorque, rodX[0].r); + + + } else if (preconditioner_=="NeumannNeumann") { + + //////////////////////////////////////////////////////////////////// + // Preconditioner is a convex combination of the linearized + // Neumann-to-Dirichlet map of the continuum and the linearized + // Neumann-to-Dirichlet map of the rod. + //////////////////////////////////////////////////////////////////// + + LinearizedContinuumNeumannToDirichletMap<typename ContinuumGridType::LevelGridView,MatrixType,VectorType> + linContNtDMap(*interfaceBoundary_, + rhs3d, + *dirichletValues_, + localAssembler_, + solver_); + + LinearizedRodNeumannToDirichletMap<typename RodGridType::LeafGridView,RodCorrectionType> linRodNtDMap(couplingBoundary, + rodLocalStiffness_); + + Dune::FieldVector<double,6> continuumCorrection = linContNtDMap.apply(x3d, residualForce, residualTorque, rodX[0].r); + Dune::FieldVector<double,6> rodCorrection = linRodNtDMap.apply(rodX, residualForce, residualTorque, rodX[0].r); + + for (int j=0; j<6; j++) + interfaceCorrection[j] = (alpha_[0] * continuumCorrection[j] + alpha_[1] * rodCorrection[j]) + / alpha_[0] + alpha_[1]; + + } else if (preconditioner_=="RobinRobin") { + + DUNE_THROW(Dune::NotImplemented, "Robin-Robin preconditioner not implemented yet"); + + } else + DUNE_THROW(Dune::NotImplemented, preconditioner_ << " is not a known preconditioner"); + + /////////////////////////////////////////////////////////////////////////////// + // Apply the damped correction to the current interface value + /////////////////////////////////////////////////////////////////////////////// + + interfaceCorrection *= richardsonDamping_; + lambda = RigidBodyMotion<3>::exp(lambda, interfaceCorrection); + +} + +#endif \ No newline at end of file -- GitLab