diff --git a/dirneucoupling.cc b/dirneucoupling.cc index 4589e8a0b60319e46c55b9e7afa3b65a1b92968a..573a0ab4b1caae44098cd881a52159f6c919c258 100644 --- a/dirneucoupling.cc +++ b/dirneucoupling.cc @@ -4,6 +4,8 @@ #include <dune/grid/uggrid.hh> #include <dune/istl/io.hh> +#include <dune/istl/solvers.hh> + #include <dune/grid/io/file/amirameshreader.hh> #include <dune/grid/io/file/amirameshwriter.hh> @@ -65,7 +67,7 @@ public: typename P1NodalBasis<GridView,double>::LocalFiniteElement, typename P1NodalBasis<GridView,double>::LocalFiniteElement, Dune::FieldMatrix<double,3,3> >* localAssembler, - const shared_ptr<LoopSolver<VectorType> >& solver + const shared_ptr< ::LoopSolver<VectorType> >& solver ) : interface_(interface), weakVolumeAndNeumannTerm_(weakVolumeAndNeumannTerm), @@ -78,9 +80,9 @@ public: * * \param currentIterate The continuum configuration that we are linearizing about * - * \return The averaged Dirichlet value + * \return The infinitesimal movement of the interface */ - RigidBodyMotion<3> apply(const VectorType& currentIterate, + 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 @@ -139,7 +141,18 @@ public: std::cout << "Average interface: " << averageInterface << std::endl; - return averageInterface; + // 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: @@ -148,7 +161,7 @@ private: const VectorType& dirichletValues_; - const shared_ptr<LoopSolver<VectorType> > solver_; + const shared_ptr< ::LoopSolver<VectorType> > solver_; const BoundaryPatchBase<GridView>& interface_; @@ -158,6 +171,111 @@ private: 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 { // Some types that I need @@ -414,7 +532,7 @@ int main (int argc, char *argv[]) try EnergyNorm<MatrixType, VectorType> energyNorm(multigridStep); - shared_ptr<LoopSolver<VectorType> > solver = shared_ptr<LoopSolver<VectorType> >( new LoopSolver<VectorType>(&multigridStep, + shared_ptr< ::LoopSolver<VectorType> > solver = shared_ptr< ::LoopSolver<VectorType> >( new ::LoopSolver<VectorType>(&multigridStep, // IPOpt doesn't like to be started in the solution (numLevels!=1) ? multigridIterations : 1, mgTolerance, @@ -628,7 +746,7 @@ int main (int argc, char *argv[]) try dirichletValues.back(), &localAssembler, solver); - averageInterface = linContNtDMap.apply(x3d, residualForce, residualTorque, rodX[0].r); + FieldVector<double,6> interfaceCorrection = linContNtDMap.apply(x3d, residualForce, residualTorque, rodX[0].r); } else if (preconditioner=="NeumannDirichlet") { @@ -636,8 +754,14 @@ int main (int argc, char *argv[]) try // Preconditioner is the linearized Neumann-to-Dirichlet map // of the rod. //////////////////////////////////////////////////////////////////// + + typedef BlockVector<FieldVector<double,6> > RodVectorType; + + LinearizedRodNeumannToDirichletMap<RodGridType::LeafGridView,RodVectorType> linRodNtDMap(couplingBoundary, + &rodLocalStiffness); + + FieldVector<double,6> interfaceCorrection = linRodNtDMap.apply(rodX, residualForce, residualTorque, rodX[0].r); - DUNE_THROW(NotImplemented, "Neumann-Dirichlet preconditioner not implemented yet"); } else if (preconditioner=="NeumannNeumann") { @@ -647,7 +771,26 @@ int main (int argc, char *argv[]) try // Neumann-to-Dirichlet map of the rod. //////////////////////////////////////////////////////////////////// - DUNE_THROW(NotImplemented, "Neumann-Neumann preconditioner not implemented yet"); + 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); + FieldVector<double,6> interfaceCorrection = continuumCorrection; + interfaceCorrection *= alpha[0]; + interfaceCorrection.axpy(alpha[1], rodCorrection); + interfaceCorrection /= alpha[0] + alpha[1]; } else if (preconditioner=="RobinRobin") {