diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 49dd39a82be03f70bff6e3e37f3ba3c6384c8122..b0fa64926e3517dacfd7dd44b82b3c64529c40e9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,12 +1,13 @@ --- -image: duneci/dune-fufem:2.4 +image: duneci/dune:2.6 + +before_script: + - duneci-install-module https://git.imp.fu-berlin.de/agnumpde/dune-matrix-vector.git + - duneci-install-module https://git.imp.fu-berlin.de/agnumpde/dune-solvers.git + - duneci-install-module https://git.imp.fu-berlin.de/agnumpde/dune-fufem.git dune-fufem--gcc: - script: - - dunecontrol --current all - - dunecontrol --current make test + script: duneci-standard-test dune-fufem--clang: - script: - - CMAKE_FLAGS="-DCMAKE_CXX_COMPILER=/usr/bin/clang++" dunecontrol --current all - - dunecontrol --current make test + script: duneci-standard-test --opts=/duneci/opts.clang diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fbd1a322c391729e9ccc28d4d8d261d0623f68a..6b1dac1137ce1bbfa9e4f9ef1adbfe559bc432ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.6) +cmake_minimum_required(VERSION 2.8.12) project(dune-gfe CXX) if(NOT (dune-common_DIR OR dune-common_ROOT OR @@ -17,7 +17,7 @@ include(DuneMacros) # start a dune project with information from dune.module dune_project() - +dune_enable_all_packages() add_subdirectory("src") add_subdirectory("dune") add_subdirectory("doc") diff --git a/dune-gfe.pc.in b/dune-gfe.pc.in index aa613574ece11eb6345c63c669159dace96886ef..5fa55f710e3a42565ae7bb9d89f9a8059be29655 100644 --- a/dune-gfe.pc.in +++ b/dune-gfe.pc.in @@ -9,6 +9,7 @@ DEPENDENCIES=@REQUIRES@ Name: @PACKAGE_NAME@ Version: @VERSION@ Description: Dune dune-gfe module, contains the implementation of geodesic finite elements -Requires: ${DEPENDENCIES} -Libs: +URL: +Requires: dune-grid dune-uggrid dune-istl dune-localfunctions dune-functions dune-solvers dune-fufem +Libs: -L${libdir} Cflags: -I${includedir} diff --git a/dune.module b/dune.module index 7184b149308fb2b7d98aa91e0d1a30dfe000ba6e..26bcb99d069dd57cf83d3f23f07f8e188620457c 100644 --- a/dune.module +++ b/dune.module @@ -1,11 +1,11 @@ - -#dune module information file# -############################## +################################ +# Dune module information file # +################################ #Name of the module -Module:dune-gfe +Module: dune-gfe Version: svn Maintainer: oliver.sander@tu-dresden.de #depending on -Depends: dune-grid dune-istl dune-localfunctions dune-functions dune-solvers dune-fufem +Depends: dune-grid dune-uggrid dune-istl dune-localfunctions dune-functions dune-solvers dune-fufem Suggests: dune-foamgrid diff --git a/dune/gfe/CMakeLists.txt b/dune/gfe/CMakeLists.txt index 7ffd4e92a85db2846bb920bb776fc5f24aebd128..0cb24b316392d5583f7624b81ebda0e1b2457bf7 100644 --- a/dune/gfe/CMakeLists.txt +++ b/dune/gfe/CMakeLists.txt @@ -1,3 +1,2 @@ #install headers -install(FILES gfe.hh DESTINATION include/dune/gfe) - +install(FILES gfe.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/gfe) diff --git a/dune/gfe/averagedistanceassembler.hh b/dune/gfe/averagedistanceassembler.hh index b4def6ba1165b4aac40784f58edd8049e2c078f9..3c23d23285b334c81971459c86a6cbd50b3af045 100644 --- a/dune/gfe/averagedistanceassembler.hh +++ b/dune/gfe/averagedistanceassembler.hh @@ -69,21 +69,6 @@ public: orthonormalFrame.mv(embeddedGradient,gradient); } - void assembleEmbeddedHessian(const TargetSpace& x, - Dune::FieldMatrix<ctype,embeddedSize,embeddedSize>& matrix) const - { - matrix = 0; - for (size_t i=0; i<coefficients_.size(); i++) { - Dune::SymmetricMatrix<ctype,embeddedSize> tmp = TargetSpace::secondDerivativeOfDistanceSquaredWRTSecondArgument(coefficients_[i], x); - for (int j=0; j<embeddedSize; j++) - for (int k=0; k<=j; k++) { - matrix[j][k] += weights_[i] * tmp(j,k); - if (j!=k) - matrix[k][j] += weights_[i] * tmp(j,k); - } - } - } - void assembleEmbeddedHessian(const TargetSpace& x, Dune::SymmetricMatrix<ctype,embeddedSize>& matrix) const { @@ -92,6 +77,7 @@ public: matrix.axpy(weights_[i], TargetSpace::secondDerivativeOfDistanceSquaredWRTSecondArgument(coefficients_[i], x)); } + // TODO Use a Symmetric matrix for the result void assembleHessian(const TargetSpace& x, Dune::FieldMatrix<ctype,size,size>& matrix) const { diff --git a/dune/gfe/averageinterface.hh b/dune/gfe/averageinterface.hh index cdcd8e83af660086ccc9b462021df575ef7ef89d..c57c98a5ab8749cae92a86a018d8377a1eaa2696 100644 --- a/dune/gfe/averageinterface.hh +++ b/dune/gfe/averageinterface.hh @@ -9,6 +9,8 @@ #include <dune/istl/solvers.hh> #include <dune/istl/preconditioners.hh> +#include dune/matrix-vector/crossproduct.hh> + #include <dune/fufem/dgindexset.hh> #include <dune/fufem/arithmetic.hh> #include <dune/fufem/surfmassmatrix.hh> @@ -500,7 +502,7 @@ void computeTotalForceAndTorque(const BoundaryPatch<GridView>& interface, neumannFunction.evaluateLocal(*it->inside(), quadPos, value); totalForce.axpy(quad[ip].weight() * integrationElement, value); - totalTorque.axpy(quad[ip].weight() * integrationElement, Arithmetic::crossProduct(worldPos-center,value)); + totalTorque.axpy(quad[ip].weight() * integrationElement, MatrixVector::crossProduct(worldPos-center,value)); } diff --git a/dune/gfe/cosseratenergystiffness.hh b/dune/gfe/cosseratenergystiffness.hh index 1ff24720b0da85f5b683c107a8a5519095989c9e..bcc3b95092dbabde8eb16a88d23ee2c6995eb0a0 100644 --- a/dune/gfe/cosseratenergystiffness.hh +++ b/dune/gfe/cosseratenergystiffness.hh @@ -45,10 +45,10 @@ public: /** \brief Specialize for scalar bases, here we cannot call tree().child() */ template <class GridView, int order, std::size_t i> -class LocalFiniteElementFactory<Dune::Functions::PQkNodalBasis<GridView,order>,i> +class LocalFiniteElementFactory<Dune::Functions::LagrangeBasis<GridView,order>,i> { public: - static auto get(const typename Dune::Functions::PQkNodalBasis<GridView,order>::LocalView& localView, + static auto get(const typename Dune::Functions::LagrangeBasis<GridView,order>::LocalView& localView, std::integral_constant<std::size_t, i> iType) -> decltype(localView.tree().finiteElement()) { diff --git a/dune/gfe/cosseratvtkwriter.hh b/dune/gfe/cosseratvtkwriter.hh index 9abe1085e076a6370fde5187a6bdedb7a7d21e6a..97239597566cf33e209608d489acf58253925f0d 100644 --- a/dune/gfe/cosseratvtkwriter.hh +++ b/dune/gfe/cosseratvtkwriter.hh @@ -1,10 +1,12 @@ #ifndef COSSERAT_VTK_WRITER_HH #define COSSERAT_VTK_WRITER_HH +#include <dune/common/version.hh> + #include <dune/grid/io/file/vtk/vtkwriter.hh> #include <dune/grid/io/file/vtk/pvtuwriter.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/functions/functionspacebases/interpolate.hh> #include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh> @@ -129,7 +131,7 @@ public: // Downsample 3rd-order functions onto a P2-space. That's all VTK can visualize today. if (order>=3) { - typedef Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,2> P2Basis; + typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,2> P2Basis; P2Basis p2Basis(gridView); std::vector<RigidBodyMotion<double,3> > downsampledConfig; @@ -147,8 +149,8 @@ public: for (const auto t : gridView.indexSet().types(0)) numElements[t] = 0; - for (auto it = gridView.template begin<0,Dune::Interior_Partition>(); it != gridView.template end<0,Dune::Interior_Partition>(); ++it) - numElements[it.type()]++; + for (auto&& t : elements(gridView, Dune::Partitions::interior)) + numElements[t.type()]++; std::size_t totalNumElements = 0; for (const auto nE : numElements) @@ -169,23 +171,30 @@ public: connectivitySize += ((vtkOrder==2) ? 8 : 4) * nE.second; else if (nE.first.isTriangle()) connectivitySize += ((vtkOrder==2) ? 6 : 3) * nE.second; + else if (nE.first.isHexahedron()) + connectivitySize += ((vtkOrder==2) ? 20 : 8) * nE.second; else DUNE_THROW(Dune::IOError, "Unsupported element type '" << nE.first << "' found!"); } std::vector<int> connectivity(connectivitySize); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis.localIndexSet(); +#endif size_t i=0; for (const auto& element : elements(gridView, Dune::Partitions::interior)) { localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif if (element.type().isQuadrilateral()) { if (vtkOrder==2) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) connectivity[i++] = localIndexSet.index(0); connectivity[i++] = localIndexSet.index(2); connectivity[i++] = localIndexSet.index(8); @@ -195,31 +204,127 @@ public: connectivity[i++] = localIndexSet.index(5); connectivity[i++] = localIndexSet.index(7); connectivity[i++] = localIndexSet.index(3); +#else + connectivity[i++] = localView.index(0); + connectivity[i++] = localView.index(2); + connectivity[i++] = localView.index(8); + connectivity[i++] = localView.index(6); + + connectivity[i++] = localView.index(1); + connectivity[i++] = localView.index(5); + connectivity[i++] = localView.index(7); + connectivity[i++] = localView.index(3); +#endif } else // first order { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) connectivity[i++] = localIndexSet.index(0); connectivity[i++] = localIndexSet.index(1); connectivity[i++] = localIndexSet.index(3); connectivity[i++] = localIndexSet.index(2); +#else + connectivity[i++] = localView.index(0); + connectivity[i++] = localView.index(1); + connectivity[i++] = localView.index(3); + connectivity[i++] = localView.index(2); +#endif } } if (element.type().isTriangle()) { if (vtkOrder==2) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) + connectivity[i++] = localIndexSet.index(0); + connectivity[i++] = localIndexSet.index(2); + connectivity[i++] = localIndexSet.index(5); + connectivity[i++] = localIndexSet.index(1); + connectivity[i++] = localIndexSet.index(4); + connectivity[i++] = localIndexSet.index(3); +#else + connectivity[i++] = localView.index(0); + connectivity[i++] = localView.index(2); + connectivity[i++] = localView.index(5); + connectivity[i++] = localView.index(1); + connectivity[i++] = localView.index(4); + connectivity[i++] = localView.index(3); +#endif + } + else // first order + { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) + connectivity[i++] = localIndexSet.index(0); + connectivity[i++] = localIndexSet.index(1); + connectivity[i++] = localIndexSet.index(2); +#else + connectivity[i++] = localView.index(0); + connectivity[i++] = localView.index(1); + connectivity[i++] = localView.index(2); +#endif + } + } + if (element.type().isHexahedron()) + { + if (vtkOrder==2) + { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) connectivity[i++] = localIndexSet.index(0); connectivity[i++] = localIndexSet.index(2); connectivity[i++] = localIndexSet.index(5); connectivity[i++] = localIndexSet.index(1); connectivity[i++] = localIndexSet.index(4); connectivity[i++] = localIndexSet.index(3); +#else + // Corner dofs + connectivity[i++] = localView.index(0); + connectivity[i++] = localView.index(2); + connectivity[i++] = localView.index(8); + connectivity[i++] = localView.index(6); + + connectivity[i++] = localView.index(18); + connectivity[i++] = localView.index(20); + connectivity[i++] = localView.index(26); + connectivity[i++] = localView.index(24); + + // Edge dofs + connectivity[i++] = localView.index(1); + connectivity[i++] = localView.index(5); + connectivity[i++] = localView.index(7); + connectivity[i++] = localView.index(3); + + connectivity[i++] = localView.index(19); + connectivity[i++] = localView.index(23); + connectivity[i++] = localView.index(25); + connectivity[i++] = localView.index(21); + + connectivity[i++] = localView.index(9); + connectivity[i++] = localView.index(11); + connectivity[i++] = localView.index(17); + connectivity[i++] = localView.index(15); +#endif } else // first order { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) connectivity[i++] = localIndexSet.index(0); connectivity[i++] = localIndexSet.index(1); + connectivity[i++] = localIndexSet.index(3); connectivity[i++] = localIndexSet.index(2); + connectivity[i++] = localIndexSet.index(4); + connectivity[i++] = localIndexSet.index(5); + connectivity[i++] = localIndexSet.index(7); + connectivity[i++] = localIndexSet.index(6); +#else + connectivity[i++] = localView.index(0); + connectivity[i++] = localView.index(1); + connectivity[i++] = localView.index(3); + connectivity[i++] = localView.index(2); + connectivity[i++] = localView.index(4); + connectivity[i++] = localView.index(5); + connectivity[i++] = localView.index(7); + connectivity[i++] = localView.index(6); +#endif } } } @@ -237,6 +342,9 @@ public: if (element.type().isTriangle()) offsetCounter += (vtkOrder==2) ? 6 : 3; + if (element.type().isHexahedron()) + offsetCounter += (vtkOrder==2) ? 20 : 8; + offsets[i++] += offsetCounter; } @@ -251,6 +359,9 @@ public: if (element.type().isTriangle()) cellTypes[i++] = (vtkOrder==2) ? 22 : 5; + + if (element.type().isHexahedron()) + cellTypes[i++] = (vtkOrder==2) ? 25 : 12; } vtkFile.cellTypes_ = cellTypes; @@ -300,7 +411,7 @@ public: std::vector<RealTuple<double,3> > displacementConfiguration = deformationConfiguration; typedef typename GridType::LeafGridView GridView; - typedef Dune::Functions::PQkNodalBasis<GridView,2> P2DeformationBasis; + typedef Dune::Functions::LagrangeBasis<GridView,2> P2DeformationBasis; P2DeformationBasis p2DeformationBasis(gridView); if (order == 3) @@ -337,7 +448,11 @@ public: // dump point coordinates writer.beginPoints(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) writer.addArray<float>("Coordinates", 3); +#else + writer.addArray("Coordinates", 3, Dune::VTK::Precision::float32); +#endif writer.endPoints(); for (int i=0; i<gridView.comm().size(); i++) @@ -352,9 +467,8 @@ public: ///////////////////////////////////////////////////////////////////////////////// // Stupid: I can't directly get the number of Interior_Partition elements - size_t numElements = 0; - for (const auto& element : elements(gridView, Dune::Partitions::interior)) - numElements++; + size_t numElements = std::distance(gridView.template begin<0, Dune::Interior_Partition>(), + gridView.template end<0, Dune::Interior_Partition>()); std::ofstream outFile(fullfilename); @@ -376,15 +490,20 @@ public: outFile << " <Cells>" << std::endl; outFile << " <DataArray type=\"Int32\" Name=\"connectivity\" NumberOfComponents=\"1\" format=\"ascii\">" << std::endl; +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = p2DeformationBasis.localIndexSet(); +#endif for (const auto& element : elements(gridView, Dune::Partitions::interior)) { localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif outFile << " "; if (element.type().isQuadrilateral()) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) outFile << localIndexSet.index(0) << " "; outFile << localIndexSet.index(2) << " "; outFile << localIndexSet.index(8) << " "; @@ -394,6 +513,17 @@ public: outFile << localIndexSet.index(5) << " "; outFile << localIndexSet.index(7) << " "; outFile << localIndexSet.index(3) << " "; +#else + outFile << localView.index(0) << " "; + outFile << localView.index(2) << " "; + outFile << localView.index(8) << " "; + outFile << localView.index(6) << " "; + + outFile << localView.index(1) << " "; + outFile << localView.index(5) << " "; + outFile << localView.index(7) << " "; + outFile << localView.index(3) << " "; +#endif outFile << std::endl; } } diff --git a/dune/gfe/embeddedglobalgfefunction.hh b/dune/gfe/embeddedglobalgfefunction.hh index 3bad3c1d3c634fe09120012245ec2c30138fe4bb..86731241e589908cbcbe83106dfdad849463a2d3 100644 --- a/dune/gfe/embeddedglobalgfefunction.hh +++ b/dune/gfe/embeddedglobalgfefunction.hh @@ -68,17 +68,25 @@ public: typename TargetSpace::CoordinateType operator()(const Element& element, const Dune::FieldVector<ctype,gridDim>& local) const { auto localView = basis_.localView(); - auto localIndexSet = basis_.localIndexSet(); localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) + auto localIndexSet = basis_.localIndexSet(); localIndexSet.bind(localView); auto numOfBaseFct = localIndexSet.size(); +#else + auto numOfBaseFct = localView.size(); +#endif // Extract local coefficients std::vector<TargetSpace> localCoeff(numOfBaseFct); for (size_t i=0; i<numOfBaseFct; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localCoeff[i] = coefficients_[localIndexSet.index(i)]; +#else + localCoeff[i] = coefficients_[localView.index(i)]; +#endif // create local gfe function LocalInterpolationRule localInterpolationRule(localView.tree().finiteElement(),localCoeff); @@ -96,17 +104,26 @@ public: Dune::FieldMatrix<ctype, embeddedDim, gridDim> derivative(const Element& element, const Dune::FieldVector<ctype,gridDim>& local) const { auto localView = basis_.localView(); - auto localIndexSet = basis_.localIndexSet(); localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) + auto localIndexSet = basis_.localIndexSet(); localIndexSet.bind(localView); int numOfBaseFct = localIndexSet.size(); +#else + auto numOfBaseFct = localView.size(); +#endif + // Extract local coefficients std::vector<TargetSpace> localCoeff(numOfBaseFct); - for (int i=0; i<numOfBaseFct; i++) + for (decltype(numOfBaseFct) i=0; i<numOfBaseFct; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localCoeff[i] = coefficients_[localIndexSet.index(i)]; +#else + localCoeff[i] = coefficients_[localView.index(i)]; +#endif // create local gfe function LocalInterpolationRule localInterpolationRule(localView.tree().finiteElement(),localCoeff); diff --git a/dune/gfe/geodesicfeassembler.hh b/dune/gfe/geodesicfeassembler.hh index ffea522fe78a18a854e46244d0d35db8be3e5d85..0e737066c64874735400fdf95ac192b77b93046f 100644 --- a/dune/gfe/geodesicfeassembler.hh +++ b/dune/gfe/geodesicfeassembler.hh @@ -76,7 +76,9 @@ getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const // A view on the FE basis on a single element auto localView = basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis_.localIndexSet(); +#endif ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>(); ElementIterator endit = basis_.gridView().template end<0,Dune::Interior_Partition> (); @@ -85,7 +87,9 @@ getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const // Bind the local FE basis view to the current element localView.bind(*it); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif const auto& lfe = localView.tree().finiteElement(); @@ -93,8 +97,13 @@ getNeighborsPerVertex(Dune::MatrixIndexSet& nb) const for (size_t j=0; j<lfe.size(); j++) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto iIdx = localIndexSet.index(i)[0]; auto jIdx = localIndexSet.index(j)[0]; +#else + auto iIdx = localView.index(i); + auto jIdx = localView.index(j); +#endif nb.add(iIdx, jIdx); @@ -128,7 +137,9 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol, // A view on the FE basis on a single element auto localView = basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis_.localIndexSet(); +#endif ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>(); ElementIterator endit = basis_.gridView().template end<0,Dune::Interior_Partition> (); @@ -136,7 +147,9 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol, for( ; it != endit; ++it ) { localView.bind(*it); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif const int numOfBaseFct = localView.tree().size(); @@ -144,7 +157,11 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol, std::vector<TargetSpace> localSolution(numOfBaseFct); for (int i=0; i<numOfBaseFct; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localSolution[i] = sol[localIndexSet.index(i)[0]]; +#else + localSolution[i] = sol[localView.index(i)]; +#endif std::vector<Dune::FieldVector<double,blocksize> > localGradient(numOfBaseFct); @@ -154,11 +171,19 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol, // Add element matrix to global stiffness matrix for(int i=0; i<numOfBaseFct; i++) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto row = localIndexSet.index(i)[0]; +#else + auto row = localView.index(i); +#endif for (int j=0; j<numOfBaseFct; j++ ) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto col = localIndexSet.index(j)[0]; +#else + auto col = localView.index(j); +#endif hessian[row][col] += localStiffness_->A_[i][j]; } @@ -166,7 +191,11 @@ assembleGradientAndHessian(const std::vector<TargetSpace>& sol, // Add local gradient to global gradient for (int i=0; i<numOfBaseFct; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) gradient[localIndexSet.index(i)[0]] += localGradient[i]; +#else + gradient[localView.index(i)] += localGradient[i]; +#endif } @@ -185,7 +214,9 @@ assembleGradient(const std::vector<TargetSpace>& sol, // A view on the FE basis on a single element auto localView = basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis_.localIndexSet(); +#endif ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>(); ElementIterator endIt = basis_.gridView().template end<0,Dune::Interior_Partition>(); @@ -194,7 +225,9 @@ assembleGradient(const std::vector<TargetSpace>& sol, for (; it!=endIt; ++it) { localView.bind(*it); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif // A 1d grid has two vertices const auto nDofs = localView.tree().size(); @@ -203,7 +236,11 @@ assembleGradient(const std::vector<TargetSpace>& sol, std::vector<TargetSpace> localSolution(nDofs); for (size_t i=0; i<nDofs; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localSolution[i] = sol[localIndexSet.index(i)[0]]; +#else + localSolution[i] = sol[localView.index(i)]; +#endif // Assemble local gradient std::vector<Dune::FieldVector<double,blocksize> > localGradient(nDofs); @@ -212,8 +249,11 @@ assembleGradient(const std::vector<TargetSpace>& sol, // Add to global gradient for (size_t i=0; i<nDofs; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) grad[localIndexSet.index(i)[0]] += localGradient[i]; - +#else + grad[localView.index(i)[0]] += localGradient[i]; +#endif } } @@ -230,7 +270,9 @@ computeEnergy(const std::vector<TargetSpace>& sol) const // A view on the FE basis on a single element auto localView = basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis_.localIndexSet(); +#endif ElementIterator it = basis_.gridView().template begin<0,Dune::Interior_Partition>(); ElementIterator endIt = basis_.gridView().template end<0,Dune::Interior_Partition>(); @@ -239,7 +281,9 @@ computeEnergy(const std::vector<TargetSpace>& sol) const for (; it!=endIt; ++it) { localView.bind(*it); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif // Number of degrees of freedom on this element size_t nDofs = localView.tree().size(); @@ -247,7 +291,11 @@ computeEnergy(const std::vector<TargetSpace>& sol) const std::vector<TargetSpace> localSolution(nDofs); for (size_t i=0; i<nDofs; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localSolution[i] = sol[localIndexSet.index(i)[0]]; +#else + localSolution[i] = sol[localView.index(i)[0]]; +#endif energy += localStiffness_->energy(localView, localSolution); diff --git a/dune/gfe/harmonicenergystiffness.hh b/dune/gfe/harmonicenergystiffness.hh index 645b519a5ad3ce17fc4cea5648d9aff54627cfc8..253bd102fda9c3fd1f60311e1e84379a306d24ad 100644 --- a/dune/gfe/harmonicenergystiffness.hh +++ b/dune/gfe/harmonicenergystiffness.hh @@ -49,25 +49,25 @@ energy(const typename Basis::LocalView& localView, // Local position of the quadrature point const Dune::FieldVector<double,gridDim>& quadPos = quad[pt].position(); - const double integrationElement = element.geometry().integrationElement(quadPos); + const auto integrationElement = element.geometry().integrationElement(quadPos); const auto jacobianInverseTransposed = element.geometry().jacobianInverseTransposed(quadPos); - double weight = quad[pt].weight() * integrationElement; + auto weight = quad[pt].weight() * integrationElement; // The derivative of the local function defined on the reference element auto referenceDerivative = localInterpolationRule.evaluateDerivative(quadPos); - // The derivative of the function defined on the actual element - typename LocalInterpolationRule::DerivativeType derivative(0); - - for (size_t comp=0; comp<referenceDerivative.N(); comp++) - jacobianInverseTransposed.umv(referenceDerivative[comp], derivative[comp]); - - // Add the local energy density - // The Frobenius norm is the correct norm here if the metric of TargetSpace is the identity. - // (And if the metric of the domain space is the identity, which it always is here.) - energy += weight * derivative.frobenius_norm2(); + // Compute the Frobenius norm squared of the derivative. This is the correct term + // if both domain and target space use the metric inherited from an embedding. + for (size_t i=0; i<jacobianInverseTransposed.N(); i++) + for (int j=0; j<TargetSpace::embeddedDim; j++) + { + RT entry = 0; + for (size_t k=0; k<jacobianInverseTransposed.M(); k++) + entry += jacobianInverseTransposed[i][k] * referenceDerivative[j][k]; + energy += weight * entry * entry; + } } diff --git a/dune/gfe/localgeodesicfefunction.hh b/dune/gfe/localgeodesicfefunction.hh index 1552f595fefad0f6710ed2a108530fe023af1011..3502f371dc54ec4756c2a7701604a6eda35d4153 100644 --- a/dune/gfe/localgeodesicfefunction.hh +++ b/dune/gfe/localgeodesicfefunction.hh @@ -111,7 +111,7 @@ public: } private: - static Dune::FieldMatrix<RT,embeddedDim,embeddedDim> pseudoInverse(const Dune::FieldMatrix<RT,embeddedDim,embeddedDim>& dFdq, + static Dune::SymmetricMatrix<RT,embeddedDim> pseudoInverse(const Dune::SymmetricMatrix<RT,embeddedDim>& dFdq, const TargetSpace& q) { const int shortDim = TargetSpace::TangentVector::dimension; @@ -120,25 +120,25 @@ private: Dune::FieldMatrix<RT,shortDim,embeddedDim> O = q.orthonormalFrame(); // compute A = O dFDq O^T + // TODO A really is symmetric, too Dune::FieldMatrix<RT,shortDim,shortDim> A; for (int i=0; i<shortDim; i++) for (int j=0; j<shortDim; j++) { A[i][j] = 0; for (int k=0; k<embeddedDim; k++) for (int l=0; l<embeddedDim; l++) - A[i][j] += O[i][k]*dFdq[k][l]*O[j][l]; + A[i][j] += O[i][k] * ((k>=l) ? dFdq(k,l) : dFdq(l,k)) *O[j][l]; } A.invert(); - Dune::FieldMatrix<RT,embeddedDim,embeddedDim> result; + Dune::SymmetricMatrix<RT,embeddedDim> result; + result = 0.0; for (int i=0; i<embeddedDim; i++) - for (int j=0; j<embeddedDim; j++) { - result[i][j] = 0; + for (int j=0; j<=i; j++) for (int k=0; k<shortDim; k++) for (int l=0; l<shortDim; l++) - result[i][j] += O[k][i]*A[k][l]*O[l][j]; - } + result(i,j) += O[k][i]*A[k][l]*O[l][j]; return result; } @@ -195,10 +195,7 @@ evaluate(const Dune::FieldVector<ctype, dim>& local) const solver.setup(&assembler, initialIterate, 1e-14, // tolerance - 100, // maxTrustRegionSteps - 2, // initial trust region radius - 100, // inner iterations - 1e-14 // inner tolerance + 100 // maxNewtonSteps ); solver.solve(); @@ -313,7 +310,7 @@ evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& loc AverageDistanceAssembler<TargetSpace> assembler(coefficients_, w); - Dune::FieldMatrix<RT,embeddedDim,embeddedDim> dFdq(0); + Dune::SymmetricMatrix<RT,embeddedDim> dFdq; assembler.assembleEmbeddedHessian(q,dFdq); const int shortDim = TargetSpace::TangentVector::dimension; @@ -328,7 +325,7 @@ evaluateDerivativeOfValueWRTCoefficient(const Dune::FieldVector<ctype, dim>& loc A[i][j] = 0; for (int k=0; k<embeddedDim; k++) for (int l=0; l<embeddedDim; l++) - A[i][j] += O[i][k]*dFdq[k][l]*O[j][l]; + A[i][j] += O[i][k] * ((k>=l) ? dFdq(k,l) : dFdq(l,k)) * O[j][l]; } // @@ -421,7 +418,7 @@ evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& AverageDistanceAssembler<TargetSpace> assembler(coefficients_, w); /** \todo Use a symmetric matrix here */ - Dune::FieldMatrix<RT,embeddedDim,embeddedDim> dFdq(0); + Dune::SymmetricMatrix<RT,embeddedDim> dFdq; assembler.assembleEmbeddedHessian(q,dFdq); @@ -436,7 +433,7 @@ evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& // dFDq is not invertible, if the target space is embedded into a higher-dimensional // Euclidean space. Therefore we use its pseudo inverse. I don't think that is the // best way, though. - Dune::FieldMatrix<RT,embeddedDim,embeddedDim> dFdqPseudoInv = pseudoInverse(dFdq,q); + Dune::SymmetricMatrix<RT,embeddedDim> dFdqPseudoInv = pseudoInverse(dFdq,q); // Tensor3<RT,embeddedDim,embeddedDim,embeddedDim> dvDqF @@ -488,7 +485,8 @@ evaluateDerivativeOfGradientWRTCoefficient(const Dune::FieldVector<ctype, dim>& for (int j=0; j<embeddedDim; j++) for (int k=0; k<dim; k++) for (int l=0; l<embeddedDim; l++) - result[i][j][k] += dFdqPseudoInv[j][l] * foo[i][l][k]; + // TODO Smarter implementation of the product with a symmetric matrix + result[i][j][k] += ((j>=l) ? dFdqPseudoInv(j,l) : dFdqPseudoInv(l,j)) * foo[i][l][k]; } @@ -623,7 +621,7 @@ public: /** \brief Evaluate the derivative of the function */ DerivativeType evaluateDerivative(const Dune::FieldVector<ctype, dim>& local) const { - Dune::FieldMatrix<ctype, embeddedDim, dim> result(0); + DerivativeType result(0); // get translation part std::vector<Dune::FieldMatrix<ctype,1,dim> > sfDer(translationCoefficients_.size()); @@ -634,7 +632,7 @@ public: result[j].axpy(translationCoefficients_[i][j], sfDer[i][0]); // get orientation part - Dune::FieldMatrix<ctype,4,dim> qResult = orientationFEFunction_->evaluateDerivative(local); + Dune::FieldMatrix<field_type,4,dim> qResult = orientationFEFunction_->evaluateDerivative(local); for (int i=0; i<4; i++) for (int j=0; j<dim; j++) result[3+i][j] = qResult[i][j]; diff --git a/dune/gfe/localgfetestfunctionbasis.hh b/dune/gfe/localgfetestfunctionbasis.hh index ed1af0a3fd5045e7447325a8824ec258b9e88cf8..60062767fbc8bfd12da4f85a5caaab81d0d58486 100644 --- a/dune/gfe/localgfetestfunctionbasis.hh +++ b/dune/gfe/localgfetestfunctionbasis.hh @@ -109,7 +109,7 @@ public : //! The local basis traits typedef Dune::LocalBasisTraits<ctype, dim, Dune::FieldVector<ctype,dim>, typename EmbeddedTangentVector::value_type, embeddedDim, std::array<EmbeddedTangentVector,spaceDim>, - std::array<Dune::FieldMatrix<ctype, embeddedDim, dim>,spaceDim>,1> Traits; + std::array<Dune::FieldMatrix<ctype, embeddedDim, dim>,spaceDim>> Traits; /** \brief Constructor */ diff --git a/dune/gfe/localquickanddirtyfefunction.hh b/dune/gfe/localquickanddirtyfefunction.hh index 277d98a33c2c4ddc33b2aace83b4dee0a3f37edc..5f46c8ad63304417666059814386400281aaf847 100644 --- a/dune/gfe/localquickanddirtyfefunction.hh +++ b/dune/gfe/localquickanddirtyfefunction.hh @@ -100,11 +100,54 @@ namespace Dune { std::vector<Dune::FieldVector<ctype,1> > w; localFiniteElement_.localBasis().evaluateFunction(local,w); - typename TargetSpace::CoordinateType c(0); - for (size_t i=0; i<coefficients_.size(); i++) - c.axpy(w[i][0], coefficients_[i].globalCoordinates()); + // Special-casing for the Rotations. This is quite a challenge: + // + // Projection-based interpolation in the + // unit quaternions is not a good idea, here, because you may end up on the + // wrong sheet of the covering of SO(3) by the unit quaternions. The minimization + // solver for the weighted distance functional may then actually converge + // to the wrong local minimizer -- the interpolating functions wraps "the wrong way" + // around SO(3). + // + // Projection-based interpolation in SO(3) is not a good idea, because it is about as + // expensive as the geodesic interpolation itself. That's not good if all we want + // is an initial iterate. + // + // Averaging in R^{3x3} followed by QR decomposition is not a good idea either: + // The averaging can give you singular matrices quite quickly (try two matrices that + // differ by a rotation of pi/2). Then, the QR factorization of the identity may + // not be the identity (but differ in sign)! I tried that with the implementation + // from Numerical recipies. + // + // What do we do instead? We start from the coefficient that produces the lowest + // value of the objective functional. + if constexpr (std::is_same<TargetSpace,Rotation<double,3> >::value) + { + AverageDistanceAssembler averageDistance(coefficients_,w); + + auto minDistance = averageDistance.value(coefficients_[0]); + std::size_t minCoefficient = 0; + + for (std::size_t i=1; i<coefficients_.size(); i++) + { + auto distance = averageDistance.value(coefficients_[i]); + if (distance < minDistance) + { + minDistance = distance; + minCoefficient = i; + } + } + + return coefficients_[minCoefficient]; + } + else + { + typename TargetSpace::CoordinateType c(0); + for (size_t i=0; i<coefficients_.size(); i++) + c.axpy(w[i][0], coefficients_[i].globalCoordinates()); - return TargetSpace(c); + return TargetSpace(c); + } } } // namespace GFE diff --git a/dune/gfe/mixedgfeassembler.hh b/dune/gfe/mixedgfeassembler.hh index 52d8dcf96386a32e8b4cfbe99ccc42f11b83c3c9..941b035f465d76b29e9fb030997a7c45b122dae2 100644 --- a/dune/gfe/mixedgfeassembler.hh +++ b/dune/gfe/mixedgfeassembler.hh @@ -95,13 +95,16 @@ getMatrixPattern(Dune::MatrixIndexSet& nb00, // A view on the FE basis on a single element auto localView = basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis_.localIndexSet(); +#endif // Loop over grid elements for (const auto& element : elements(basis_.gridView(), Dune::Partitions::interior)) { // Bind the local FE basis view to the current element localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); // Add element stiffness matrix onto the global stiffness matrix @@ -114,6 +117,18 @@ getMatrixPattern(Dune::MatrixIndexSet& nb00, { // The global index of the j-th local degree of freedom of the element 'e' auto col = localIndexSet.index(j); +#else + // Add element stiffness matrix onto the global stiffness matrix + for (size_t i=0; i<localView.size(); i++) + { + // The global index of the i-th local degree of freedom of the element 'e' + auto row = localView.index(i); + + for (size_t j=0; j<localView.size(); j++ ) + { + // The global index of the j-th local degree of freedom of the element 'e' + auto col = localView.index(j); +#endif if (row[0]==0 and col[0]==0) nb00.add(row[1],col[1]); @@ -167,13 +182,17 @@ assembleGradientAndHessian(const std::vector<TargetSpace0>& configuration0, // A view on the FE basis on a single element auto localView = basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis_.localIndexSet(); +#endif for (const auto& element : elements(basis_.gridView(), Dune::Partitions::interior)) { // Bind the local FE basis view to the current element localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif using namespace Dune::TypeTree::Indices; const int nDofs0 = localView.tree().child(_0).finiteElement().size(); @@ -185,10 +204,17 @@ assembleGradientAndHessian(const std::vector<TargetSpace0>& configuration0, for (int i=0; i<nDofs0+nDofs1; i++) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) if (localIndexSet.index(i)[0] == 0) localConfiguration0[i] = configuration0[localIndexSet.index(i)[1]]; else localConfiguration1[i-nDofs0] = configuration1[localIndexSet.index(i)[1]]; +#else + if (localView.index(i)[0] == 0) + localConfiguration0[i] = configuration0[localView.index(i)[1]]; + else + localConfiguration1[i-nDofs0] = configuration1[localView.index(i)[1]]; +#endif } std::vector<Dune::FieldVector<double,blocksize0> > localGradient0(nDofs0); @@ -202,11 +228,19 @@ assembleGradientAndHessian(const std::vector<TargetSpace0>& configuration0, // Add element matrix to global stiffness matrix for (int i=0; i<nDofs0+nDofs1; i++) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto row = localIndexSet.index(i); +#else + auto row = localView.index(i); +#endif for (int j=0; j<nDofs0+nDofs1; j++ ) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto col = localIndexSet.index(j); +#else + auto col = localView.index(j); +#endif if (row[0]==0 and col[0]==0) hessian[_0][_0][row[1]][col[1]] += localStiffness_->A00_[i][j]; @@ -222,10 +256,17 @@ assembleGradientAndHessian(const std::vector<TargetSpace0>& configuration0, } // Add local gradient to global gradient +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) if (localIndexSet.index(i)[0] == 0) gradient0[localIndexSet.index(i)[1]] += localGradient0[i]; else gradient1[localIndexSet.index(i)[1]] += localGradient1[i-nDofs0]; +#else + if (localView.index(i)[0] == 0) + gradient0[localView.index(i)[1]] += localGradient0[i]; + else + gradient1[localView.index(i)[1]] += localGradient1[i-nDofs0]; +#endif } } @@ -287,14 +328,18 @@ computeEnergy(const std::vector<TargetSpace0>& configuration0, // A view on the FE basis on a single element auto localView = basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = basis_.localIndexSet(); +#endif // Loop over all elements for (const auto& element : elements(basis_.gridView(), Dune::Partitions::interior)) { // Bind the local FE basis view to the current element localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif // Number of degrees of freedom on this element using namespace Dune::TypeTree::Indices; @@ -306,10 +351,17 @@ computeEnergy(const std::vector<TargetSpace0>& configuration0, for (int i=0; i<nDofs0+nDofs1; i++) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) if (localIndexSet.index(i)[0] == 0) localConfiguration0[i] = configuration0[localIndexSet.index(i)[1]]; else localConfiguration1[i-nDofs0] = configuration1[localIndexSet.index(i)[1]]; +#else + if (localView.index(i)[0] == 0) + localConfiguration0[i] = configuration0[localView.index(i)[1]]; + else + localConfiguration1[i-nDofs0] = configuration1[localView.index(i)[1]]; +#endif } energy += localStiffness_->energy(localView, diff --git a/dune/gfe/mixedriemanniantrsolver.cc b/dune/gfe/mixedriemanniantrsolver.cc index 5282aaa6d4127534f13d93d093af6951ce8fba30..dff40c95860ada21929500f252d4af44dd57de5d 100644 --- a/dune/gfe/mixedriemanniantrsolver.cc +++ b/dune/gfe/mixedriemanniantrsolver.cc @@ -6,7 +6,7 @@ #include <dune/istl/io.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/fufem/functionspacebases/dunefunctionsbasis.hh> #include <dune/fufem/assemblers/operatorassembler.hh> #include <dune/fufem/assemblers/localassemblers/laplaceassembler.hh> @@ -81,12 +81,12 @@ setup(const GridType& grid, // //////////////////////////////// #ifdef HAVE_IPOPT // First create an IPOpt base solver - auto baseSolver0 = new QuadraticIPOptSolver<MatrixType00,CorrectionType0>; - baseSolver0->verbosity_ = NumProc::QUIET; - baseSolver0->tolerance_ = baseTolerance; - auto baseSolver1 = new QuadraticIPOptSolver<MatrixType11,CorrectionType1>; - baseSolver1->verbosity_ = NumProc::QUIET; - baseSolver1->tolerance_ = baseTolerance; + auto baseSolver0 = std::make_shared<QuadraticIPOptSolver<MatrixType00,CorrectionType0>>(); + baseSolver0->setVerbosity(NumProc::QUIET); + baseSolver0->setTolerance(baseTolerance); + auto baseSolver1 = std::make_shared<QuadraticIPOptSolver<MatrixType11,CorrectionType1>>(); + baseSolver1->setVerbosity(NumProc::QUIET); + baseSolver1->setTolerance(baseTolerance); #else // First create a Gauss-seidel base solver TrustRegionGSStep<MatrixType00, CorrectionType0>* baseSolverStep0 = new TrustRegionGSStep<MatrixType00, CorrectionType0>; @@ -122,29 +122,29 @@ setup(const GridType& grid, // Make pre and postsmoothers - TrustRegionGSStep<MatrixType00, CorrectionType0>* presmoother0 = new TrustRegionGSStep<MatrixType00, CorrectionType0>; - TrustRegionGSStep<MatrixType00, CorrectionType0>* postsmoother0 = new TrustRegionGSStep<MatrixType00, CorrectionType0>; + auto presmoother0 = std::make_shared<TrustRegionGSStep<MatrixType00, CorrectionType0> >(); + auto postsmoother0 = std::make_shared<TrustRegionGSStep<MatrixType00, CorrectionType0> >(); mmgStep0 = new MonotoneMGStep<MatrixType00, CorrectionType0>; mmgStep0->setMGType(mu, nu1, nu2); mmgStep0->ignoreNodes_ = globalDirichletNodes0; - mmgStep0->basesolver_ = baseSolver0; + mmgStep0->setBaseSolver(baseSolver0); mmgStep0->setSmoother(presmoother0, postsmoother0); - mmgStep0->obstacleRestrictor_= new MandelObstacleRestrictor<CorrectionType0>(); - mmgStep0->verbosity_ = Solver::QUIET; + mmgStep0->setObstacleRestrictor(std::make_shared<MandelObstacleRestrictor<CorrectionType0>>()); + mmgStep0->setVerbosity(Solver::QUIET); - TrustRegionGSStep<MatrixType11, CorrectionType1>* presmoother1 = new TrustRegionGSStep<MatrixType11, CorrectionType1>; - TrustRegionGSStep<MatrixType11, CorrectionType1>* postsmoother1 = new TrustRegionGSStep<MatrixType11, CorrectionType1>; + auto presmoother1 = std::make_shared<TrustRegionGSStep<MatrixType11, CorrectionType1> >(); + auto postsmoother1 = std::make_shared<TrustRegionGSStep<MatrixType11, CorrectionType1> >(); mmgStep1 = new MonotoneMGStep<MatrixType11, CorrectionType1>; mmgStep1->setMGType(mu, nu1, nu2); mmgStep1->ignoreNodes_ = globalDirichletNodes1; - mmgStep1->basesolver_ = baseSolver1; + mmgStep1->setBaseSolver(baseSolver1); mmgStep1->setSmoother(presmoother1, postsmoother1); - mmgStep1->obstacleRestrictor_= new MandelObstacleRestrictor<CorrectionType1>(); - mmgStep1->verbosity_ = Solver::QUIET; + mmgStep1->setObstacleRestrictor(std::make_shared<MandelObstacleRestrictor<CorrectionType1>>()); + mmgStep1->setVerbosity(Solver::QUIET); // ////////////////////////////////////////////////////////////////////////////////////// // Assemble a Laplace matrix to create a norm that's equivalent to the H1-norm @@ -193,12 +193,6 @@ setup(const GridType& grid, // Create the transfer operators // //////////////////////////////////// - for (size_t k=0; k<mmgStep0->mgTransfer_.size(); k++) - delete(mmgStep0->mgTransfer_[k]); - - for (size_t k=0; k<mmgStep1->mgTransfer_.size(); k++) - delete(mmgStep1->mgTransfer_[k]); - mmgStep0->mgTransfer_.resize(numLevels-1); mmgStep1->mgTransfer_.resize(numLevels-1); @@ -206,20 +200,20 @@ setup(const GridType& grid, { if (numLevels>1) { typedef typename TruncatedCompressedMGTransfer<CorrectionType0>::TransferOperatorType TransferOperatorType; - DuneFunctionsBasis<Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> > p1Basis(grid_->leafGridView()); + DuneFunctionsBasis<Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> > p1Basis(grid_->leafGridView()); TransferOperatorType pkToP1TransferMatrix; assembleBasisInterpolationMatrix<TransferOperatorType, - DuneFunctionsBasis<Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> >, + DuneFunctionsBasis<Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> >, FufemBasis0>(pkToP1TransferMatrix,p1Basis,*basis0_); - mmgStep0->mgTransfer_.back() = new TruncatedCompressedMGTransfer<CorrectionType0>; + mmgStep0->mgTransfer_.back() = std::make_shared<TruncatedCompressedMGTransfer<CorrectionType0>>(); Dune::shared_ptr<TransferOperatorType> topTransferOperator = Dune::make_shared<TransferOperatorType>(pkToP1TransferMatrix); - dynamic_cast<TruncatedCompressedMGTransfer<CorrectionType0>*>(mmgStep0->mgTransfer_.back())->setMatrix(topTransferOperator); + std::dynamic_pointer_cast<TruncatedCompressedMGTransfer<CorrectionType0>>(mmgStep0->mgTransfer_.back())->setMatrix(topTransferOperator); for (size_t i=0; i<mmgStep0->mgTransfer_.size()-1; i++){ // Construct the local multigrid transfer matrix - TruncatedCompressedMGTransfer<CorrectionType0>* newTransferOp0 = new TruncatedCompressedMGTransfer<CorrectionType0>; + auto newTransferOp0 = std::make_shared<TruncatedCompressedMGTransfer<CorrectionType0>>(); newTransferOp0->setup(*grid_,i+1,i+2); mmgStep0->mgTransfer_[i] = newTransferOp0; @@ -234,7 +228,7 @@ setup(const GridType& grid, for (size_t i=0; i<mmgStep0->mgTransfer_.size(); i++){ // Construct the local multigrid transfer matrix - TruncatedCompressedMGTransfer<CorrectionType0>* newTransferOp0 = new TruncatedCompressedMGTransfer<CorrectionType0>; + auto newTransferOp0 = std::make_shared<TruncatedCompressedMGTransfer<CorrectionType0>>(); newTransferOp0->setup(*grid_,i,i+1); mmgStep0->mgTransfer_[i] = newTransferOp0; @@ -246,20 +240,20 @@ setup(const GridType& grid, { if (numLevels>1) { typedef typename TruncatedCompressedMGTransfer<CorrectionType1>::TransferOperatorType TransferOperatorType; - DuneFunctionsBasis<Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> > p1Basis(grid_->leafGridView()); + DuneFunctionsBasis<Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> > p1Basis(grid_->leafGridView()); TransferOperatorType pkToP1TransferMatrix; assembleBasisInterpolationMatrix<TransferOperatorType, - DuneFunctionsBasis<Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> >, + DuneFunctionsBasis<Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> >, FufemBasis1>(pkToP1TransferMatrix,p1Basis,*basis1_); - mmgStep1->mgTransfer_.back() = new TruncatedCompressedMGTransfer<CorrectionType1>; - Dune::shared_ptr<TransferOperatorType> topTransferOperator = Dune::make_shared<TransferOperatorType>(pkToP1TransferMatrix); - dynamic_cast<TruncatedCompressedMGTransfer<CorrectionType1>*>(mmgStep1->mgTransfer_.back())->setMatrix(topTransferOperator); + mmgStep1->mgTransfer_.back() = std::make_shared<TruncatedCompressedMGTransfer<CorrectionType1>>(); + std::shared_ptr<TransferOperatorType> topTransferOperator = std::make_shared<TransferOperatorType>(pkToP1TransferMatrix); + std::dynamic_pointer_cast<TruncatedCompressedMGTransfer<CorrectionType1>>(mmgStep1->mgTransfer_.back())->setMatrix(topTransferOperator); for (size_t i=0; i<mmgStep1->mgTransfer_.size()-1; i++){ // Construct the local multigrid transfer matrix - TruncatedCompressedMGTransfer<CorrectionType1>* newTransferOp1 = new TruncatedCompressedMGTransfer<CorrectionType1>; + auto newTransferOp1 = std::make_shared<TruncatedCompressedMGTransfer<CorrectionType1>>(); newTransferOp1->setup(*grid_,i+1,i+2); mmgStep1->mgTransfer_[i] = newTransferOp1; } @@ -273,7 +267,7 @@ setup(const GridType& grid, for (size_t i=0; i<mmgStep1->mgTransfer_.size(); i++){ // Construct the local multigrid transfer matrix - TruncatedCompressedMGTransfer<CorrectionType1>* newTransferOp = new TruncatedCompressedMGTransfer<CorrectionType1>; + auto newTransferOp = std::make_shared<TruncatedCompressedMGTransfer<CorrectionType1>>(); newTransferOp->setup(*grid_,i,i+1); mmgStep1->mgTransfer_[i] = newTransferOp; } @@ -291,8 +285,8 @@ setup(const GridType& grid, hasObstacle0_.resize(assembler->basis_.size({0}), true); hasObstacle1_.resize(assembler->basis_.size({1}), true); #endif - mmgStep0->hasObstacle_ = &hasObstacle0_; - mmgStep1->hasObstacle_ = &hasObstacle1_; + mmgStep0->setHasObstacles(hasObstacle0_); + mmgStep1->setHasObstacles(hasObstacle1_); } } @@ -403,13 +397,13 @@ void MixedRiemannianTrustRegionSolver<GridType,Basis,Basis0,TargetSpace0,Basis1, mmgStep0->setProblem(stiffnessMatrix[_0][_0], corr_global[_0], residual[_0]); trustRegionObstacles0 = trustRegion0.obstacles(); - mmgStep0->obstacles_ = &trustRegionObstacles0; + mmgStep0->setObstacles(trustRegionObstacles0); mmgStep0->preprocess(); mmgStep1->setProblem(stiffnessMatrix[_1][_1], corr_global[_1], residual[_1]); trustRegionObstacles1 = trustRegion1.obstacles(); - mmgStep1->obstacles_ = &trustRegionObstacles1; + mmgStep1->setObstacles(trustRegionObstacles1); mmgStep1->preprocess(); diff --git a/dune/gfe/mixedriemanniantrsolver.hh b/dune/gfe/mixedriemanniantrsolver.hh index d291e0e8a7b40c6bd83759b85ed9261169120e6a..197388783636b2427c11172d5cfb546e5f36d8c3 100644 --- a/dune/gfe/mixedriemanniantrsolver.hh +++ b/dune/gfe/mixedriemanniantrsolver.hh @@ -11,7 +11,7 @@ #include <dune/grid/utility/globalindexset.hh> -#include <dune/functions/common/tuplevector.hh> +#include <dune/common/tuplevector.hh> #include <dune/solvers/common/boxconstraint.hh> #include <dune/solvers/norms/h1seminorm.hh> @@ -47,7 +47,7 @@ class MixedRiemannianTrustRegionSolver typedef Dune::BlockVector<Dune::FieldVector<field_type, blocksize0> > CorrectionType0; typedef Dune::BlockVector<Dune::FieldVector<field_type, blocksize1> > CorrectionType1; typedef Dune::MultiTypeBlockVector<CorrectionType0, CorrectionType1> CorrectionType; - typedef Dune::Functions::TupleVector<std::vector<TargetSpace0>, std::vector<TargetSpace1> > SolutionType; + typedef Dune::TupleVector<std::vector<TargetSpace0>, std::vector<TargetSpace1> > SolutionType; public: diff --git a/dune/gfe/nonplanarcosseratshellenergy.hh b/dune/gfe/nonplanarcosseratshellenergy.hh index b995ccaa9c677e98a15d9cb6c704ecd50bff6e17..7378f35614ae49253c39431f16f711830aa95718 100644 --- a/dune/gfe/nonplanarcosseratshellenergy.hh +++ b/dune/gfe/nonplanarcosseratshellenergy.hh @@ -5,6 +5,8 @@ #include <dune/common/parametertree.hh> #include <dune/geometry/quadraturerules.hh> +#include <dune/matrix-vector/crossproduct.hh> + #include <dune/fufem/functions/virtualgridfunction.hh> #include <dune/fufem/boundarypatch.hh> @@ -277,7 +279,7 @@ energy(const typename Basis::LocalView& localView, const auto& localFiniteElement = localView.tree().finiteElement(); //////////////////////////////////////////////////////////////////////////////////// - // Construct a linear (i.e., non-constant!) normal field on the surface + // Construct a linear (i.e., non-constant!) normal field on each element //////////////////////////////////////////////////////////////////////////////////// auto gridView = localView.globalBasis().gridView(); @@ -312,8 +314,6 @@ energy(const typename Basis::LocalView& localView, const DT integrationElement = geometry.integrationElement(quadPos); - DT weight = quad[pt].weight() * integrationElement; - // The value of the local function RigidBodyMotion<field_type,dim> value = localGeodesicFEFunction.evaluate(quadPos); @@ -351,7 +351,7 @@ energy(const typename Basis::LocalView& localView, aCovariant[i][j] = 0.0; } - aCovariant[2] = Arithmetic::crossProduct(aCovariant[0], aCovariant[1]); + aCovariant[2] = Dune::MatrixVector::crossProduct(aCovariant[0], aCovariant[1]); aCovariant[2] /= aCovariant[2].two_norm(); auto aContravariant = aCovariant; @@ -428,15 +428,18 @@ energy(const typename Basis::LocalView& localView, ////////////////////////////////////////////////////////// // Add the membrane energy density - energy += weight * (thickness_ - K*Dune::Power<3>::eval(thickness_) / 12.0) * W_m(Ee) - + weight * (Dune::Power<3>::eval(thickness_) / 12.0 - K * Dune::Power<5>::eval(thickness_) / 80.0)*W_m(Ee*b + c*Ke) - + weight * Dune::Power<3>::eval(thickness_) / 6.0 * W_mixt(Ee, c*Ke*b - 2*H*c*Ke) - + weight * Dune::Power<5>::eval(thickness_) / 80.0 * W_mp( (Ee*b + c*Ke)*b); + auto energyDensity = (thickness_ - K*Dune::Power<3>::eval(thickness_) / 12.0) * W_m(Ee) + + (Dune::Power<3>::eval(thickness_) / 12.0 - K * Dune::Power<5>::eval(thickness_) / 80.0)*W_m(Ee*b + c*Ke) + + Dune::Power<3>::eval(thickness_) / 6.0 * W_mixt(Ee, c*Ke*b - 2*H*c*Ke) + + Dune::Power<5>::eval(thickness_) / 80.0 * W_mp( (Ee*b + c*Ke)*b); // Add the bending energy density - energy += weight * (thickness_ - K*Dune::Power<3>::eval(thickness_) / 12.0) * W_curv(Ke) - + weight * (Dune::Power<3>::eval(thickness_) / 12.0 - K * Dune::Power<5>::eval(thickness_) / 80.0)*W_curv(Ke*b) - + weight * Dune::Power<5>::eval(thickness_) / 80.0 * W_curv(Ke*b*b); + energyDensity += (thickness_ - K*Dune::Power<3>::eval(thickness_) / 12.0) * W_curv(Ke) + + (Dune::Power<3>::eval(thickness_) / 12.0 - K * Dune::Power<5>::eval(thickness_) / 80.0)*W_curv(Ke*b) + + Dune::Power<5>::eval(thickness_) / 80.0 * W_curv(Ke*b*b); + + // Add energy density + energy += quad[pt].weight() * integrationElement * energyDensity; /////////////////////////////////////////////////////////// // Volume load contribution diff --git a/dune/gfe/parallel/globalp1mapper.hh b/dune/gfe/parallel/globalp1mapper.hh index 8e1371798ce300c90082f66614fd4ac557ffa86e..e7da2815b0f19eb91479592c20c2663d525585ff 100644 --- a/dune/gfe/parallel/globalp1mapper.hh +++ b/dune/gfe/parallel/globalp1mapper.hh @@ -14,11 +14,6 @@ // Include Dune header files #include <dune/common/version.hh> -/** include parallel capability */ -#if HAVE_MPI - #include <dune/common/parallel/mpihelper.hh> -#endif - namespace Dune { template <class GridView> diff --git a/dune/gfe/parallel/globalp2mapper.hh b/dune/gfe/parallel/globalp2mapper.hh index a2f636baeda94c00fd4be074f3e7ac5787a7c12c..1bb6a3ede3732e9e59d3c1e50b1cc0b586ebe1f1 100644 --- a/dune/gfe/parallel/globalp2mapper.hh +++ b/dune/gfe/parallel/globalp2mapper.hh @@ -14,12 +14,7 @@ // Include Dune header files #include <dune/common/version.hh> -/** include parallel capability */ -#if HAVE_MPI - #include <dune/common/parallel/mpihelper.hh> -#endif - -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> namespace Dune { @@ -38,6 +33,9 @@ namespace Dune { { static_assert(GridView::dimension==2, "Only implemented for two-dimensional grids"); + if (gridView.size(GeometryTypes::triangle)>1) + DUNE_THROW(NotImplemented, "GlobalP2Mapper only works for quad grids!"); + GlobalIndexSet<GridView> globalVertexIndex(gridView,2); GlobalIndexSet<GridView> globalEdgeIndex(gridView,1); GlobalIndexSet<GridView> globalElementIndex(gridView,0); @@ -46,21 +44,33 @@ namespace Dune { size_ = globalVertexIndex.size(2) + globalEdgeIndex.size(1) + globalElementIndex.size(0); auto localView = p2Mapper_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = p2Mapper_.localIndexSet(); +#endif // Determine for (const auto& element : elements(gridView)) { localView.bind(element); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif // Loop over all local degrees of freedom +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) for (size_t i=0; i<localIndexSet.size(); i++) +#else + for (size_t i=0; i<localView.size(); i++) +#endif { int codim = localView.tree().finiteElement().localCoefficients().localKey(i).codim(); int entity = localView.tree().finiteElement().localCoefficients().localKey(i).subEntity(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) int localIndex = localIndexSet.index(i); +#else + auto localIndex = localView.index(i); +#endif int globalIndex; switch (codim) { @@ -105,19 +115,29 @@ namespace Dune { bool contains(const Entity& entity, uint subEntity, uint codim, Index& result) const { auto localView = p2Mapper_.localView(); - auto localIndexSet = p2Mapper_.localIndexSet(); localView.bind(entity); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) + auto localIndexSet = p2Mapper_.localIndexSet(); localIndexSet.bind(localView); +#endif Index localIndex; bool dofFound = false; +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) for (size_t i=0; i<localIndexSet.size(); i++) +#else + for (size_t i=0; i<localView.size(); i++) +#endif { if (localView.tree().finiteElement().localCoefficients().localKey(i).subEntity() == subEntity and localView.tree().finiteElement().localCoefficients().localKey(i).codim() == codim) { dofFound = true; +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndex = localIndexSet.index(i); +#else + localIndex = localView.index(i); +#endif break; } } @@ -134,14 +154,13 @@ namespace Dune { return size_; } - Functions::PQkNodalBasis<GridView,2> p2Mapper_; + Functions::LagrangeBasis<GridView,2> p2Mapper_; IndexMap localGlobalMap_; - size_t nOwnedLocalEntity_; size_t size_; }; } -#endif /* GLOBALUNIQUEINDEX_HH_ */ +#endif // DUNE_GFE_PARALLEL_GLOBALP2MAPPER_HH diff --git a/dune/gfe/parallel/p2mapper.hh b/dune/gfe/parallel/p2mapper.hh index d6eed91ebe341a57b976ac1e2707cb2f09932e4e..3f9384d3e290c001006b964790c47ebd4ef303c3 100644 --- a/dune/gfe/parallel/p2mapper.hh +++ b/dune/gfe/parallel/p2mapper.hh @@ -6,7 +6,7 @@ #include <dune/geometry/type.hh> #include <dune/common/typetraits.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> /** \brief Mimic a dune-grid mapper for a P2 space, using the dune-functions dof ordering of such a space */ @@ -16,7 +16,7 @@ class P2BasisMapper typedef typename GridView::Grid::template Codim<0>::Entity Element; public: - typedef typename Dune::Functions::PQkNodalBasis<GridView,2>::MultiIndex::value_type Index; + typedef typename Dune::Functions::LagrangeBasis<GridView,2>::MultiIndex::value_type Index; P2BasisMapper(const GridView& gridView) : p2Basis_(gridView) @@ -31,18 +31,26 @@ public: bool contains(const Entity& entity, uint subEntity, uint codim, Index& result) const { auto localView = p2Basis_.localView(); - auto localIndexSet = p2Basis_.localIndexSet(); localView.bind(entity); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) + auto localIndexSet = p2Basis_.localIndexSet(); localIndexSet.bind(localView); +#endif - Index localIndex; +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) for (size_t i=0; i<localIndexSet.size(); i++) +#else + for (size_t i=0; i<localView.size(); i++) +#endif { if (localView.tree().finiteElement().localCoefficients().localKey(i).subEntity() == subEntity and localView.tree().finiteElement().localCoefficients().localKey(i).codim() == codim) { - localIndex = i; +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) result = localIndexSet.index(i)[0]; +#else + result = localView.index(i); +#endif return true; } } @@ -50,7 +58,7 @@ public: return false; } - Dune::Functions::PQkNodalBasis<GridView,2> p2Basis_; + Dune::Functions::LagrangeBasis<GridView,2> p2Basis_; }; #endif diff --git a/dune/gfe/periodic1dpq1nodalbasis.hh b/dune/gfe/periodic1dpq1nodalbasis.hh index df31bc5a67c23c10d7fe27cab0d3aecdbef85844..78852d98420986db2c232baa51986842ebd47e41 100644 --- a/dune/gfe/periodic1dpq1nodalbasis.hh +++ b/dune/gfe/periodic1dpq1nodalbasis.hh @@ -7,11 +7,9 @@ #include <dune/localfunctions/lagrange/pqkfactory.hh> -#include <dune/typetree/leafnode.hh> - #include <dune/functions/functionspacebases/nodes.hh> -#include <dune/functions/functionspacebases/defaultglobalbasis.hh> #include <dune/functions/functionspacebases/flatmultiindex.hh> +#include <dune/functions/functionspacebases/defaultglobalbasis.hh> namespace Dune { @@ -20,48 +18,46 @@ namespace Functions { // ***************************************************************************** // This is the reusable part of the basis. It contains // -// PQ1NodeFactory +// PQ1PreBasis // PQ1NodeIndexSet // PQ1Node // -// The factory allows to create the others and is the owner of possible shared +// The pre-basis allows to create the others and is the owner of possible shared // state. These three components do _not_ depend on the global basis or index // set and can be used without a global basis. // ***************************************************************************** -template<typename GV, typename ST, typename TP> +template<typename GV> class Periodic1DPQ1Node; -template<typename GV, class MI, class TP, class ST> +template<typename GV, class MI> class Periodic1DPQ1NodeIndexSet; -template<typename GV, class MI, class ST> -class Periodic1DPQ1NodeFactory; - -template<typename GV, class MI, class ST> -class Periodic1DPQ1NodeFactory +template<typename GV, class MI> +class Periodic1DPQ1PreBasis { static const int dim = GV::dimension; public: - /** \brief The grid view that the FE space is defined on */ + //! The grid view that the FE basis is defined on using GridView = GV; - using size_type = ST; - template<class TP> - using Node = Periodic1DPQ1Node<GV, size_type, TP>; + //! Type used for indices and size information + using size_type = std::size_t; - template<class TP> - using IndexSet = Periodic1DPQ1NodeIndexSet<GV, MI, TP, ST>; + using Node = Periodic1DPQ1Node<GV>; + + using IndexSet = Periodic1DPQ1NodeIndexSet<GV, MI>; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; - using SizePrefix = Dune::ReservedVector<size_type, 2>; + //! Type used for prefixes handed to the size() method + using SizePrefix = Dune::ReservedVector<size_type, 1>; - /** \brief Constructor for a given grid view object */ - Periodic1DPQ1NodeFactory(const GridView& gv) : + //! Constructor for a given grid view object + Periodic1DPQ1PreBasis(const GridView& gv) : gridView_(gv) {} @@ -75,16 +71,20 @@ public: return gridView_; } - template<class TP> - Node<TP> node(const TP& tp) const + //! Update the stored grid view, to be called if the grid has changed + void update (const GridView& gv) + { + gridView_ = gv; + } + + Node makeNode() const { - return Node<TP>{tp}; + return Node{}; } - template<class TP> - IndexSet<TP> indexSet() const + IndexSet makeIndexSet() const { - return IndexSet<TP>{*this}; + return IndexSet{*this}; } size_type size() const @@ -102,7 +102,7 @@ public: DUNE_THROW(RangeError, "Method size() can only be called for prefixes of length up to one"); } - /** \todo This method has been added to the interface without prior discussion. */ + //! Get the total dimension of the space spanned by this basis size_type dimension() const { return size()-1; @@ -119,25 +119,22 @@ public: -template<typename GV, typename ST, typename TP> +template<typename GV> class Periodic1DPQ1Node : - public LeafBasisNode<ST, TP> + public LeafBasisNode { static const int dim = GV::dimension; static const int maxSize = StaticPower<2,GV::dimension>::power; - using Base = LeafBasisNode<ST,TP>; using FiniteElementCache = typename Dune::PQkLocalFiniteElementCache<typename GV::ctype, double, dim, 1>; public: - using size_type = ST; - using TreePath = TP; + using size_type = std::size_t; using Element = typename GV::template Codim<0>::Entity; using FiniteElement = typename FiniteElementCache::FiniteElementType; - Periodic1DPQ1Node(const TreePath& treePath) : - Base(treePath), + Periodic1DPQ1Node() : finiteElement_(nullptr), element_(nullptr) {} @@ -174,24 +171,25 @@ protected: -template<typename GV, class MI, class TP, class ST> +template<typename GV, class MI> class Periodic1DPQ1NodeIndexSet { enum {dim = GV::dimension}; public: - using size_type = ST; + using size_type = std::size_t; /** \brief Type used for global numbering of the basis vectors */ using MultiIndex = MI; - using NodeFactory = Periodic1DPQ1NodeFactory<GV, MI, ST>; + using PreBasis = Periodic1DPQ1PreBasis<GV, MI>; - using Node = typename NodeFactory::template Node<TP>; + using Node = Periodic1DPQ1Node<GV>; - Periodic1DPQ1NodeIndexSet(const NodeFactory& nodeFactory) : - nodeFactory_(&nodeFactory) + Periodic1DPQ1NodeIndexSet(const PreBasis& preBasis) : + preBasis_(&preBasis), + node_(nullptr) {} /** \brief Bind the view to a grid element @@ -215,6 +213,7 @@ public: */ size_type size() const { + assert(node_ != nullptr); return node_->finiteElement().size(); } @@ -222,7 +221,7 @@ public: MultiIndex index(size_type i) const { Dune::LocalKey localKey = node_->finiteElement().localCoefficients().localKey(i); - const auto& gridIndexSet = nodeFactory_->gridView().indexSet(); + const auto& gridIndexSet = preBasis_->gridView().indexSet(); const auto& element = node_->element(); //return {{ gridIndexSet.subIndex(element,localKey.subEntity(),dim) }}; @@ -237,18 +236,18 @@ public: } protected: - const NodeFactory* nodeFactory_; + const PreBasis* preBasis_; const Node* node_; }; /** \brief Nodal basis of a scalar first-order Lagrangian finite element space + * on a one-dimensional domain with periodic boundary conditions * * \tparam GV The GridView that the space is defined on - * \tparam ST The type used for local indices; global indices are FlatMultiIndex<ST> */ -template<typename GV, class ST = std::size_t> -using Periodic1DPQ1NodalBasis = DefaultGlobalBasis<Periodic1DPQ1NodeFactory<GV, FlatMultiIndex<ST>, ST> >; +template<typename GV> +using Periodic1DPQ1NodalBasis = DefaultGlobalBasis<Periodic1DPQ1PreBasis<GV, FlatMultiIndex<std::size_t> > >; } // end namespace Functions } // end namespace Dune diff --git a/dune/gfe/riemanniantrsolver.cc b/dune/gfe/riemanniantrsolver.cc index 1f53e565ad5abfb5560b098ae973c9003d37804b..0c3958e0a2176c154dde43b6e5708e7c2bffc606 100644 --- a/dune/gfe/riemanniantrsolver.cc +++ b/dune/gfe/riemanniantrsolver.cc @@ -5,7 +5,6 @@ #include <dune/grid/common/mcmgmapper.hh> -#include <dune/functions/functionspacebases/pq1nodalbasis.hh> #include <dune/fufem/functionspacebases/dunefunctionsbasis.hh> #include <dune/fufem/assemblers/operatorassembler.hh> #include <dune/fufem/assemblers/localassemblers/laplaceassembler.hh> @@ -66,7 +65,7 @@ setup(const GridType& grid, ////////////////////////////////////////////////////////////////// #if HAVE_MPI - globalMapper_ = std::unique_ptr<GlobalMapper>(new GlobalMapper(grid_->leafGridView())); + globalMapper_ = std::make_unique<GlobalMapper>(grid_->leafGridView()); #endif // //////////////////////////////// @@ -130,7 +129,7 @@ setup(const GridType& grid, operatorAssembler.assemble(laplaceStiffness, localA); #if HAVE_MPI - LocalMapper localMapper(grid_->leafGridView()); + LocalMapper localMapper = MapperFactory<typename Basis::GridView,Basis>::createLocalMapper(grid_->leafGridView()); MatrixCommunicator<GlobalMapper, typename GridType::LeafGridView, @@ -195,7 +194,7 @@ setup(const GridType& grid, // On the lower grid levels a hierarchy of P1/Q1 spaces is used again. //////////////////////////////////////////////////////////////////////// - bool isP1Basis = std::is_same<Basis,Dune::Functions::PQkNodalBasis<typename Basis::GridView,1> >::value; + bool isP1Basis = std::is_same<Basis,Dune::Functions::LagrangeBasis<typename Basis::GridView,1> >::value; if (isP1Basis) mmgStep->mgTransfer_.resize(numLevels-1); @@ -206,11 +205,11 @@ setup(const GridType& grid, if (not isP1Basis) { typedef typename TruncatedCompressedMGTransfer<CorrectionType>::TransferOperatorType TransferOperatorType; - DuneFunctionsBasis<Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> > p1Basis(grid_->leafGridView()); + DuneFunctionsBasis<Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> > p1Basis(grid_->leafGridView()); TransferOperatorType pkToP1TransferMatrix; assembleBasisInterpolationMatrix<TransferOperatorType, - DuneFunctionsBasis<Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> >, + DuneFunctionsBasis<Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> >, FufemBasis>(pkToP1TransferMatrix,p1Basis,basis); #if HAVE_MPI // If we are on more than 1 processors, join all local transfer matrices on rank 0, @@ -218,8 +217,8 @@ setup(const GridType& grid, typedef Dune::GlobalP1Mapper<typename GridType::LeafGridView> GlobalLeafP1Mapper; GlobalLeafP1Mapper p1Index(grid_->leafGridView()); - typedef Dune::MultipleCodimMultipleGeomTypeMapper<typename GridType::LeafGridView, Dune::MCMGVertexLayout> LeafP1LocalMapper; - LeafP1LocalMapper leafP1LocalMapper(grid_->leafGridView()); + typedef Dune::MultipleCodimMultipleGeomTypeMapper<typename GridType::LeafGridView> LeafP1LocalMapper; + LeafP1LocalMapper leafP1LocalMapper(grid_->leafGridView(), Dune::mcmgVertexLayout()); MatrixCommunicator<GlobalMapper, typename GridType::LeafGridView, @@ -251,9 +250,9 @@ setup(const GridType& grid, GlobalLevelP1Mapper fineGUIndex(grid_->levelGridView(i+1)); GlobalLevelP1Mapper coarseGUIndex(grid_->levelGridView(i)); - typedef Dune::MultipleCodimMultipleGeomTypeMapper<typename GridType::LevelGridView, Dune::MCMGVertexLayout> LevelLocalMapper; - LevelLocalMapper fineLevelLocalMapper(grid_->levelGridView(i+1)); - LevelLocalMapper coarseLevelLocalMapper(grid_->levelGridView(i)); + typedef Dune::MultipleCodimMultipleGeomTypeMapper<typename GridType::LevelGridView> LevelLocalMapper; + LevelLocalMapper fineLevelLocalMapper(grid_->levelGridView(i+1), Dune::mcmgVertexLayout()); + LevelLocalMapper coarseLevelLocalMapper(grid_->levelGridView(i), Dune::mcmgVertexLayout()); #endif typedef typename TruncatedCompressedMGTransfer<CorrectionType>::TransferOperatorType TransferOperatorType; #if HAVE_MPI @@ -296,12 +295,12 @@ void RiemannianTrustRegionSolver<Basis,TargetSpace>::solve() { int rank = grid_->comm().rank(); - std::shared_ptr<MonotoneMGStep<MatrixType,CorrectionType> > mgStep; + MonotoneMGStep<MatrixType,CorrectionType>* mgStep = nullptr; // Non-shared pointer -- the innerSolver keeps the ownership // if the inner solver is a monotone multigrid set up a max-norm trust-region if (dynamic_cast<LoopSolver<CorrectionType>*>(innerSolver_.get())) { auto loopSolver = std::dynamic_pointer_cast<LoopSolver<CorrectionType> >(innerSolver_); - mgStep = std::dynamic_pointer_cast<MonotoneMGStep<MatrixType,CorrectionType> >(loopSolver->iterationStep_); + mgStep = dynamic_cast<MonotoneMGStep<MatrixType,CorrectionType>*>(&loopSolver->getIterationStep()); } @@ -348,7 +347,7 @@ void RiemannianTrustRegionSolver<Basis,TargetSpace>::solve() grid_->leafGridView().comm(), 0); - LocalMapper localMapper(grid_->leafGridView()); + LocalMapper localMapper = MapperFactory<typename Basis::GridView,Basis>::createLocalMapper(grid_->leafGridView()); MatrixCommunicator<GlobalMapper, typename GridType::LeafGridView, typename GridType::LeafGridView, diff --git a/dune/gfe/riemanniantrsolver.hh b/dune/gfe/riemanniantrsolver.hh index 36e61e7077577646e1d7bfd7202d78e8b86048e7..add3d56d61c31853ab262531d23a93892bd08b1a 100644 --- a/dune/gfe/riemanniantrsolver.hh +++ b/dune/gfe/riemanniantrsolver.hh @@ -8,6 +8,8 @@ #include <dune/istl/bcrsmatrix.hh> #include <dune/istl/bvector.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> + #include <dune/solvers/common/boxconstraint.hh> #include <dune/solvers/norms/h1seminorm.hh> #include <dune/solvers/solvers/iterativesolver.hh> @@ -26,12 +28,16 @@ template <typename GridView, typename Basis> struct MapperFactory {}; -/** \brief Specialization for PQ1NodalBasis */ +/** \brief Specialization for LagrangeBasis<1> */ template <typename GridView> -struct MapperFactory<GridView, Dune::Functions::PQkNodalBasis<GridView,1> > +struct MapperFactory<GridView, Dune::Functions::LagrangeBasis<GridView,1> > { typedef Dune::GlobalP1Mapper<GridView> GlobalMapper; typedef Dune::MultipleCodimMultipleGeomTypeMapper<GridView> LocalMapper; + static LocalMapper createLocalMapper(const GridView& gridView) + { + return LocalMapper(gridView, Dune::mcmgVertexLayout()); + } }; // This case is not going to actually work, but I need the specialization to make @@ -44,15 +50,19 @@ struct MapperFactory<GridView, Dune::Functions::Periodic1DPQ1NodalBasis<GridView }; template <typename GridView> -struct MapperFactory<GridView, Dune::Functions::PQkNodalBasis<GridView,2> > +struct MapperFactory<GridView, Dune::Functions::LagrangeBasis<GridView,2> > { typedef Dune::GlobalP2Mapper<GridView> GlobalMapper; typedef P2BasisMapper<GridView> LocalMapper; + static LocalMapper createLocalMapper(const GridView& gridView) + { + return LocalMapper(gridView); + } }; -/** \brief Specialization for PQ3NodalBasis */ +/** \brief Specialization for LagrangeBasis<3> */ template <typename GridView> -struct MapperFactory<GridView, Dune::Functions::PQkNodalBasis<GridView,3> > +struct MapperFactory<GridView, Dune::Functions::LagrangeBasis<GridView,3> > { // Error: we don't currently have a global P3 mapper }; diff --git a/dune/gfe/rodassembler.cc b/dune/gfe/rodassembler.cc index 558d284f8d4427d17cadfd8403eac1205ca8d492..9fef383e8321c874f2dde938c47329462e534de7 100644 --- a/dune/gfe/rodassembler.cc +++ b/dune/gfe/rodassembler.cc @@ -26,7 +26,9 @@ assembleGradient(const std::vector<RigidBodyMotion<double,3> >& sol, // A view on the FE basis on a single element auto localView = this->basis_.localView(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) auto localIndexSet = this->basis_.localIndexSet(); +#endif ElementIterator it = this->basis_.gridView().template begin<0>(); ElementIterator endIt = this->basis_.gridView().template end<0>(); @@ -35,7 +37,9 @@ assembleGradient(const std::vector<RigidBodyMotion<double,3> >& sol, for (; it!=endIt; ++it) { localView.bind(*it); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localIndexSet.bind(localView); +#endif // A 1d grid has two vertices static const int nDofs = 2; @@ -44,7 +48,11 @@ assembleGradient(const std::vector<RigidBodyMotion<double,3> >& sol, std::vector<RigidBodyMotion<double,3> > localSolution(nDofs); for (int i=0; i<nDofs; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) localSolution[i] = sol[localIndexSet.index(i)[0]]; +#else + localSolution[i] = sol[localView.index(i)]; +#endif // Assemble local gradient std::vector<FieldVector<double,blocksize> > localGradient(nDofs); @@ -55,7 +63,11 @@ assembleGradient(const std::vector<RigidBodyMotion<double,3> >& sol, // Add to global gradient for (int i=0; i<nDofs; i++) +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) grad[localIndexSet.index(i)[0]] += localGradient[i]; +#else + grad[localView.index(i)] += localGradient[i]; +#endif } diff --git a/dune/gfe/rodfactory.hh b/dune/gfe/rodfactory.hh index edfd47705fd4132f10c7fb19867fce4fdce975e8..94e06e451f012a8fe396f6124877f578a59d0624 100644 --- a/dune/gfe/rodfactory.hh +++ b/dune/gfe/rodfactory.hh @@ -5,6 +5,8 @@ #include <dune/common/fvector.hh> #include <dune/fufem/arithmetic.hh> +#include <dune/matrix-vector/crossproduct.hh> + #include <dune/gfe/rigidbodymotion.hh> #include <dune/gfe/localgeodesicfefunction.hh> @@ -39,7 +41,7 @@ template <int dim> Dune::FieldVector<double,3> zAxis(0); zAxis[2] = 1; - Dune::FieldVector<double,3> axis = Arithmetic::crossProduct(Dune::FieldVector<double,3>(end-beginning), zAxis); + Dune::FieldVector<double,3> axis = MatrixVector::crossProduct(Dune::FieldVector<double,3>(end-beginning), zAxis); if (axis.two_norm() != 0) axis /= -axis.two_norm(); diff --git a/dune/gfe/rodlocalstiffness.hh b/dune/gfe/rodlocalstiffness.hh index c215606277aa95e56c815b1be69c44286a90d70e..8d268fbd4ec251a107dbf9dd4a52f367bf464643 100644 --- a/dune/gfe/rodlocalstiffness.hh +++ b/dune/gfe/rodlocalstiffness.hh @@ -7,17 +7,17 @@ #include <dune/istl/matrix.hh> #include <dune/geometry/quadraturerules.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include "localgeodesicfestiffness.hh" #include "rigidbodymotion.hh" template<class GridView, class RT> class RodLocalStiffness - : public LocalGeodesicFEStiffness<Dune::Functions::PQkNodalBasis<GridView,1>, RigidBodyMotion<RT,3> > + : public LocalGeodesicFEStiffness<Dune::Functions::LagrangeBasis<GridView,1>, RigidBodyMotion<RT,3> > { typedef RigidBodyMotion<RT,3> TargetSpace; - typedef Dune::Functions::PQkNodalBasis<GridView,1> Basis; + typedef Dune::Functions::LagrangeBasis<GridView,1> Basis; // grid types typedef typename GridView::Grid::ctype DT; @@ -63,13 +63,10 @@ public: //! Constructor RodLocalStiffness (const GridView& gridView, const std::array<double,3>& K, const std::array<double,3>& A) - : gridView_(gridView) - { - for (int i=0; i<3; i++) { - K_[i] = K[i]; - A_[i] = A[i]; - } - } + : K_(K), + A_(A), + gridView_(gridView) + {} /** \brief Constructor setting shape constants and material parameters \param A The rod section area @@ -465,7 +462,7 @@ getStrain(const std::vector<RigidBodyMotion<RT,3> >& localSolution, // multiply with jacobian inverse Dune::FieldVector<double,1> tmp(0); inv.umv(shapeGrad[dof][0], tmp); - shapeGrad[dof] = tmp; + shapeGrad[dof][0] = tmp; } diff --git a/dune/gfe/rotation.hh b/dune/gfe/rotation.hh index 1d9bb430fc1dfdc7df2662a53c1453134059bdf8..aa023750e5188f60422f3d30f516b97b443e5cec 100644 --- a/dune/gfe/rotation.hh +++ b/dune/gfe/rotation.hh @@ -892,6 +892,27 @@ public: } + /** \brief Derivative of the map from unit quaternions to orthogonal matrices + */ + static Tensor3<T,3,3,4> derivativeOfQuaternionToMatrix(const Dune::FieldVector<T,4>& p) + { + Tensor3<T,3,3,4> result; + + result[0][0] = { 2*p[0], -2*p[1], -2*p[2], 2*p[3]}; + result[0][1] = { 2*p[1], 2*p[0], -2*p[3], -2*p[2]}; + result[0][2] = { 2*p[2], 2*p[3], 2*p[0], 2*p[1]}; + + result[1][0] = { 2*p[1], 2*p[0], 2*p[3], 2*p[2]}; + result[1][1] = {-2*p[0], 2*p[1], -2*p[2], 2*p[3]}; + result[1][2] = {-2*p[3], 2*p[2], 2*p[1], -2*p[0]}; + + result[2][0] = { 2*p[2], -2*p[3], 2*p[0], -2*p[1]}; + result[2][1] = { 2*p[3], 2*p[2], 2*p[1], 2*p[0]}; + result[2][2] = {-2*p[0], -2*p[1], 2*p[2], 2*p[3]}; + + return result; + } + /** \brief Set rotation from orthogonal matrix We tacitly assume that the matrix really is orthogonal */ @@ -1127,6 +1148,30 @@ public: return result; } + /** \brief Project a vector in R^4 onto the unit quaternions + * + * \warning This is NOT the standard projection from R^{3 \times 3} onto SO(3)! + */ + static Rotation<T,3> projectOnto(const CoordinateType& p) + { + Rotation<T,3> result(p); + result /= result.two_norm(); + return result; + } + + /** \brief Derivative of the projection of a vector in R^4 onto the unit quaternions + * + * \warning This is NOT the standard projection from R^{3 \times 3} onto SO(3)! + */ + static auto derivativeOfProjection(const Dune::FieldVector<T,4>& p) + { + Dune::FieldMatrix<T,4,4> result; + for (int i=0; i<4; i++) + for (int j=0; j<4; j++) + result[i][j] = ( (i==j) - p[i]*p[j] / p.two_norm2() ) / p.two_norm(); + return result; + } + /** \brief The global coordinates, if you really want them */ const CoordinateType& globalCoordinates() const { return *this; diff --git a/dune/gfe/symmetricmatrix.hh b/dune/gfe/symmetricmatrix.hh index d6d32d7cddd4cd1ed791ea7eb0b37f0173694aec..a8d847bb45e34d10d7a466544112f0b4346a8f78 100644 --- a/dune/gfe/symmetricmatrix.hh +++ b/dune/gfe/symmetricmatrix.hh @@ -23,10 +23,7 @@ public: enum {blocklevel = 0}; - /** \brief Default constructor - * - * Tensor is initialized containing zeros if no argument is given. - * \param eye if true tensor is initialized as identity + /** \brief Default constructor, creates uninitialized matrix */ SymmetricMatrix() {} @@ -47,7 +44,7 @@ public: * \param i line index * \param j column index * \note You need to know what you are doing: You can only access the lower - * left triangular submatrix using this methods. It requires i<=j. + * left triangular submatrix using this methods. It requires i>=j. */ T& operator() (int i, int j) { @@ -59,7 +56,7 @@ public: * \param i line index * \param j column index * \note You need to know what you are doing: You can only access the lower - * left triangular submatrix using this methods. It requires i<=j. + * left triangular submatrix using this methods. It requires i>=j. */ const T& operator() (int i, int j) const { diff --git a/dune/gfe/targetspacertrsolver.cc b/dune/gfe/targetspacertrsolver.cc index 2e11e9ea3c6a5c490c7e717302dd0513763af07f..b00b59e1b3d4e79c3a1c56786ae26ea0b7a9e883 100644 --- a/dune/gfe/targetspacertrsolver.cc +++ b/dune/gfe/targetspacertrsolver.cc @@ -13,39 +13,14 @@ void TargetSpaceRiemannianTRSolver<TargetSpace>:: setup(const AverageDistanceAssembler<TargetSpace>* assembler, const TargetSpace& x, double tolerance, - int maxTrustRegionSteps, - double initialTrustRegionRadius, - int innerIterations, - double innerTolerance) + int maxNewtonSteps) { assembler_ = assembler; x_ = x; tolerance_ = tolerance; - maxTrustRegionSteps_ = maxTrustRegionSteps; - initialTrustRegionRadius_ = initialTrustRegionRadius; - innerIterations_ = innerIterations; - innerTolerance_ = innerTolerance; + maxNewtonSteps_ = maxNewtonSteps; this->verbosity_ = NumProc::QUIET; minNumberOfIterations_ = 1; - -#ifdef USE_GAUSS_SEIDEL_SOLVER - // //////////////////////////////// - // Create a projected gauss-seidel solver - // //////////////////////////////// - - // First create a Gauss-seidel base solver - innerSolverStep_ = std::auto_ptr<TrustRegionGSStep<MatrixType, CorrectionType> >(new TrustRegionGSStep<MatrixType, CorrectionType>); - - energyNorm_ = std::auto_ptr<EnergyNorm<MatrixType, CorrectionType> >(new EnergyNorm<MatrixType, CorrectionType>(*innerSolverStep_.get())); - - innerSolver_ = std::auto_ptr< ::LoopSolver<CorrectionType> >(new ::LoopSolver<CorrectionType>(innerSolverStep_.get(), - innerIterations, - innerTolerance, - energyNorm_.get(), - Solver::QUIET)); - - innerSolver_->useRelativeError_ = false; -#endif } @@ -54,68 +29,34 @@ void TargetSpaceRiemannianTRSolver<TargetSpace>::solve() { assert(minNumberOfIterations_ > 0); - MaxNormTrustRegion<blocksize,field_type> trustRegion(1, // we have only one block - initialTrustRegionRadius_); - - field_type energy = assembler_->value(x_); - // ///////////////////////////////////////////////////// - // Trust-Region Solver + // Newton Solver // ///////////////////////////////////////////////////// - for (size_t i=0; i<maxTrustRegionSteps_; i++) { + for (size_t i=0; i<maxNewtonSteps_; i++) { if (this->verbosity_ == Solver::FULL) { std::cout << "----------------------------------------------------" << std::endl; - std::cout << " Trust-Region Step Number: " << i - << ", radius: " << trustRegion.radius() - << ", energy: " << energy << std::endl; + std::cout << " Newton Step Number: " << i + << ", energy: " << assembler_->value(x_) << std::endl; std::cout << "----------------------------------------------------" << std::endl; } - CorrectionType rhs(1); // length is 1 _block_ - CorrectionType corr(1); // length is 1 _block_ -#ifdef USE_GAUSS_SEIDEL_SOLVER - corr = 0; -#endif + CorrectionType corr; - MatrixType hesseMatrix(1,1); + MatrixType hesseMatrix; -#ifdef USE_GAUSS_SEIDEL_SOLVER - assembler_->assembleGradient(x_, rhs[0]); - assembler_->assembleHessian(x_, hesseMatrix[0][0]); -#else - /** \todo Fix this sense copying */ - typename TargetSpace::EmbeddedTangentVector foo; - assembler_->assembleEmbeddedGradient(x_, foo); - rhs[0] = foo; - assembler_->assembleEmbeddedHessian(x_, hesseMatrix[0][0]); -#endif + typename TargetSpace::EmbeddedTangentVector rhs; + assembler_->assembleEmbeddedGradient(x_, rhs); + assembler_->assembleEmbeddedHessian(x_, hesseMatrix); // The right hand side is the _negative_ gradient rhs *= -1; -#ifdef USE_GAUSS_SEIDEL_SOLVER - dynamic_cast<LinearIterationStep<MatrixType,CorrectionType>*>(innerSolver_->iterationStep_)->setProblem(hesseMatrix, corr, rhs); - - dynamic_cast<TrustRegionGSStep<MatrixType,CorrectionType>*>(innerSolver_->iterationStep_)->obstacles_ = &trustRegion.obstacles(); - - innerSolver_->preprocess(); -#endif // ///////////////////////////// // Solve ! // ///////////////////////////// -#ifdef USE_GAUSS_SEIDEL_SOLVER - innerSolver_->solve(); -#else Dune::FieldMatrix<field_type,blocksize,embeddedBlocksize> basis = x_.orthonormalFrame(); - GramSchmidtSolver<field_type, blocksize, embeddedBlocksize>::solve(hesseMatrix[0][0], corr[0], rhs[0], basis); -#endif - -#ifdef USE_GAUSS_SEIDEL_SOLVER - corr = innerSolver_->iterationStep_->getSol(); -#endif - - //std::cout << "Corr: " << corr << std::endl; + GramSchmidtSolver<field_type, blocksize, embeddedBlocksize>::solve(hesseMatrix, corr, rhs, basis); if (this->verbosity_ == NumProc::FULL) std::cout << "Infinity norm of the correction: " << corr.infinity_norm() << std::endl; @@ -125,84 +66,31 @@ void TargetSpaceRiemannianTRSolver<TargetSpace>::solve() std::cout << "CORRECTION IS SMALL ENOUGH" << std::endl; if (this->verbosity_ != NumProc::QUIET) - std::cout << i+1 << " trust-region steps were taken." << std::endl; + std::cout << i+1 << " Newton steps were taken." << std::endl; break; } // //////////////////////////////////////////////////// // Check whether trust-region step can be accepted // //////////////////////////////////////////////////// - +#if 0 TargetSpace newIterate = x_; - newIterate = TargetSpace::exp(newIterate, corr[0]); - - field_type oldEnergy = energy; - field_type energy = assembler_->value(newIterate); - - // compute the model decrease - // It is $ m(x) - m(x+s) = -<g,s> - 0.5 <s, Hs> - // Note that rhs = -g -#ifdef USE_GAUSS_SEIDEL_SOLVER - CorrectionType tmp(corr.size()); - tmp = 0; - hesseMatrix.umv(corr, tmp); - field_type modelDecrease = (rhs*corr) - 0.5 * (corr*tmp); -#else - field_type modelDecrease = (rhs*corr) - 0.5 * hesseMatrix[0][0].energyScalarProduct(corr[0],corr[0]); -#endif + newIterate = TargetSpace::exp(newIterate, corr); - if (this->verbosity_ == NumProc::FULL) { - std::cout << "Absolute model decrease: " << modelDecrease - << ", functional decrease: " << oldEnergy - energy << std::endl; - std::cout << "Relative model decrease: " << modelDecrease / energy - << ", functional decrease: " << (oldEnergy - energy)/energy << std::endl; - } - - assert(modelDecrease >= -1e-15); + if (this->verbosity_ == NumProc::FULL) + { + field_type oldEnergy = assembler_->value(x_); + field_type energy = assembler_->value(newIterate); - if (energy >= oldEnergy) { - if (this->verbosity_ == NumProc::FULL) + if (energy >= oldEnergy) printf("Richtung ist keine Abstiegsrichtung!\n"); } - if (energy >= oldEnergy && - i>minNumberOfIterations_-1 && - (std::abs(oldEnergy-energy)/energy < 1e-9 || modelDecrease/energy < 1e-9)) { - if (this->verbosity_ == NumProc::FULL) - std::cout << "Suspecting rounding problems" << std::endl; - - if (this->verbosity_ != NumProc::QUIET) - std::cout << i+1 << " trust-region steps were taken." << std::endl; - - x_ = newIterate; - break; - } - - // ////////////////////////////////////////////// - // Check for acceptance of the step - // ////////////////////////////////////////////// - if ( (oldEnergy-energy) / modelDecrease > 0.9) { - // very successful iteration - - x_ = newIterate; - trustRegion.scale(2); - - } else if ( (oldEnergy-energy) / modelDecrease > 0.01 - || std::abs(oldEnergy-energy) < 1e-12) { - // successful iteration - x_ = newIterate; - - } else { - // unsuccessful iteration - trustRegion.scale(0.5); - if (this->verbosity_ == NumProc::FULL) - std::cout << "Unsuccessful iteration!" << std::endl; - } - - // Write current energy - if (this->verbosity_ == NumProc::FULL) - std::cout << "--- Current energy: " << energy << " ---" << std::endl; - + // Actually take the step + x_ = newIterate; +#else + x_ = TargetSpace::exp(x_, corr); +#endif } } diff --git a/dune/gfe/targetspacertrsolver.hh b/dune/gfe/targetspacertrsolver.hh index 10e2d87f60f9b6e29bc7dca3b8d05b72156ed133..568d8314ac7912b66d48d124c9aafca0bf9f2689 100644 --- a/dune/gfe/targetspacertrsolver.hh +++ b/dune/gfe/targetspacertrsolver.hh @@ -1,17 +1,7 @@ #ifndef TARGET_SPACE_RIEMANNIAN_TRUST_REGION_SOLVER_HH #define TARGET_SPACE_RIEMANNIAN_TRUST_REGION_SOLVER_HH - -//#define USE_GAUSS_SEIDEL_SOLVER - -#include <dune/istl/matrix.hh> - -#include <dune/solvers/common/boxconstraint.hh> -#ifdef USE_GAUSS_SEIDEL_SOLVER -#include <dune/solvers/solvers/loopsolver.hh> -#include <dune/solvers/iterationsteps/trustregiongsstep.hh> -#endif -#include <dune/solvers/norms/energynorm.hh> +#include <dune/solvers/common/numproc.hh> #include <dune/gfe/symmetricmatrix.hh> @@ -28,31 +18,16 @@ class TargetSpaceRiemannianTRSolver // Centralize the field type here typedef typename TargetSpace::ctype field_type; - // Some types that I need - // The types have the dynamic outer type because the dune-solvers solvers expect - // this sort of type. -#ifdef USE_GAUSS_SEIDEL_SOLVER - typedef Dune::Matrix<Dune::FieldMatrix<field_type, blocksize, blocksize> > MatrixType; - typedef Dune::BlockVector<Dune::FieldVector<field_type, blocksize> > CorrectionType; -#else - typedef Dune::Matrix<Dune::SymmetricMatrix<field_type, embeddedBlocksize> > MatrixType; - typedef Dune::BlockVector<Dune::FieldVector<field_type, embeddedBlocksize> > CorrectionType; -#endif + typedef Dune::SymmetricMatrix<field_type, embeddedBlocksize> MatrixType; + typedef Dune::FieldVector<field_type, embeddedBlocksize> CorrectionType; public: - TargetSpaceRiemannianTRSolver() - // : IterativeSolver<std::vector<TargetSpace>, Dune::BitSetVector<blocksize> >(0,100,NumProc::FULL) - {} - /** \brief Set up the solver using a monotone multigrid method as the inner solver */ void setup(const AverageDistanceAssembler<TargetSpace>* assembler, const TargetSpace& x, double tolerance, - int maxTrustRegionSteps, - double initialTrustRegionRadius, - int innerIterations, - double innerTolerance); + int maxNewtonSteps); void solve(); @@ -70,32 +45,13 @@ protected: /** \brief Tolerance of the solver */ double tolerance_; - /** \brief The initial trust-region radius in the maximum-norm */ - double initialTrustRegionRadius_; - - /** \brief Maximum number of trust-region steps */ - size_t maxTrustRegionSteps_; - - /** \brief Maximum number of multigrid iterations */ - int innerIterations_; - - /** \brief Error tolerance of the multigrid QP solver */ - double innerTolerance_; + /** \brief Maximum number of Newton steps */ + size_t maxNewtonSteps_; /** \brief The assembler for the average-distance functional */ const AverageDistanceAssembler<TargetSpace>* assembler_; -#ifdef USE_GAUSS_SEIDEL_SOLVER - /** \brief The solver for the quadratic inner problems */ - std::auto_ptr< ::LoopSolver<CorrectionType> > innerSolver_; - - /** \brief The iteration step for the quadratic inner problems */ - std::auto_ptr<TrustRegionGSStep<MatrixType, CorrectionType> > innerSolverStep_; - - /** \brief Norm for the quadratic inner problems */ - std::auto_ptr<EnergyNorm<MatrixType, CorrectionType> > energyNorm_; -#endif - /** \brief Specify a minimal number of iterations the trust-region solver has to do + /** \brief Specify a minimal number of iterations the Newton solver has to do * * This is needed when working with automatic differentiation. While a very low * number of iterations may be enough to precisely compute the value of a diff --git a/dune/gfe/tensorssd.hh b/dune/gfe/tensorssd.hh index 43680fe5e7283f00ba434c1a59de2b9cda2893e4..ac83b94ce4d57e7721b1e6bed113f62101043eca 100644 --- a/dune/gfe/tensorssd.hh +++ b/dune/gfe/tensorssd.hh @@ -8,7 +8,8 @@ #include <array> #include <dune/common/fmatrix.hh> - +#include <dune/istl/matrix.hh> + /** \brief A third-rank tensor with two static (SS) and one dynamic (D) dimension * * \tparam T Type of the entries diff --git a/dune/gfe/unitvector.hh b/dune/gfe/unitvector.hh index a1145af47f0c2f1990cd7031e6bbaedeeb8ac1cc..734188488d5accf9b290a535ec518148507d1350 100644 --- a/dune/gfe/unitvector.hh +++ b/dune/gfe/unitvector.hh @@ -413,10 +413,13 @@ public: static DerivativeOfProjection derivativeOfProjection(const Dune::FieldVector<T,N>& p) { + auto normSquared = p.two_norm2(); + auto norm = std::sqrt(normSquared); + Dune::FieldMatrix<T,N,N> result; for (int i=0; i<N; i++) for (int j=0; j<N; j++) - result[i][j] = ( (i==j) - p[i]*p[j] / p.two_norm2() ) / p.two_norm(); + result[i][j] = ( (i==j) - p[i]*p[j] / normSquared ) / norm; return result; } diff --git a/dune/gfe/vertexnormals.hh b/dune/gfe/vertexnormals.hh index fb899e0ee3af64a1e4ca608727db615999d0c113..ac067464b5bc2a3c36d4397dff7330b582f4d6eb 100644 --- a/dune/gfe/vertexnormals.hh +++ b/dune/gfe/vertexnormals.hh @@ -9,6 +9,8 @@ #include <dune/geometry/referenceelements.hh> +#include <dune/matrix-vector/crossproduct.hh> + #include <dune/gfe/unitvector.hh> /** \brief Compute averaged vertex normals for a 2d-in-3d grid @@ -25,11 +27,11 @@ std::vector<UnitVector<typename GridView::ctype,3> > computeVertexNormals(const for (const auto& element : elements(gridView)) { - for (int i=0; i<element.subEntities(2); i++) + for (std::size_t i=0; i<element.subEntities(2); i++) { auto cornerPos = Dune::ReferenceElements<double,2>::general(element.type()).position(i,2); auto tangent = element.geometry().jacobianTransposed(cornerPos); - auto cornerNormal = Arithmetic::crossProduct(tangent[0], tangent[1]); + auto cornerNormal = Dune::MatrixVector::crossProduct(tangent[0], tangent[1]); cornerNormal /= cornerNormal.two_norm(); unscaledNormals[indexSet.subIndex(element,i,2)] += cornerNormal; @@ -50,4 +52,4 @@ std::vector<UnitVector<typename GridView::ctype,3> > computeVertexNormals(const } -#endif \ No newline at end of file +#endif diff --git a/dune/gfe/vtkfile.hh b/dune/gfe/vtkfile.hh index db460f03996d8b96b01e1324a14d9c3b3a99348e..cf14e8ef653547c5f879bcf459f138c3cf5707e6 100644 --- a/dune/gfe/vtkfile.hh +++ b/dune/gfe/vtkfile.hh @@ -12,6 +12,7 @@ #endif #include <dune/common/fvector.hh> +#include <dune/common/version.hh> // For parallel infrastructure stuff: #include <dune/grid/io/file/vtk.hh> @@ -55,19 +56,34 @@ namespace Dune { writer.beginMain(); writer.beginPointData(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) writer.addArray<float>("director0", 3); writer.addArray<float>("director1", 3); writer.addArray<float>("director2", 3); writer.addArray<float>("zCoord", 1); +#else + writer.addArray("director0", 3, VTK::Precision::float32); + writer.addArray("director1", 3, VTK::Precision::float32); + writer.addArray("director2", 3, VTK::Precision::float32); + writer.addArray("zCoord", 1, VTK::Precision::float32); +#endif writer.endPointData(); writer.beginCellData(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) writer.addArray<float>("mycelldata", 1); +#else + writer.addArray("mycelldata", 1, VTK::Precision::float32); +#endif writer.endCellData(); // dump point coordinates writer.beginPoints(); +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) writer.addArray<float>("Coordinates", 3); +#else + writer.addArray("Coordinates", 3, VTK::Precision::float32); +#endif writer.endPoints(); for (int i=0; i<mpiHelper.size(); i++) @@ -88,7 +104,11 @@ namespace Dune { // Write vertex coordinates outFile << " <Points>" << std::endl; { // extra parenthesis to control destruction of the pointsWriter object +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) Dune::VTK::AsciiDataArrayWriter<float> pointsWriter(outFile, "Coordinates", 3, Dune::Indent(4)); +#else + Dune::VTK::AsciiDataArrayWriter pointsWriter(outFile, "Coordinates", 3, Dune::Indent(4), VTK::Precision::float32); +#endif for (size_t i=0; i<points_.size(); i++) for (int j=0; j<3; j++) pointsWriter.write(points_[i][j]); @@ -98,19 +118,31 @@ namespace Dune { // Write elements outFile << " <Cells>" << std::endl; { // extra parenthesis to control destruction of the cellConnectivityWriter object +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) Dune::VTK::AsciiDataArrayWriter<int> cellConnectivityWriter(outFile, "connectivity", 1, Dune::Indent(4)); +#else + Dune::VTK::AsciiDataArrayWriter cellConnectivityWriter(outFile, "connectivity", 1, Dune::Indent(4), VTK::Precision::int32); +#endif for (size_t i=0; i<cellConnectivity_.size(); i++) cellConnectivityWriter.write(cellConnectivity_[i]); } { // extra parenthesis to control destruction of the writer object +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) Dune::VTK::AsciiDataArrayWriter<int> cellOffsetsWriter(outFile, "offsets", 1, Dune::Indent(4)); +#else + Dune::VTK::AsciiDataArrayWriter cellOffsetsWriter(outFile, "offsets", 1, Dune::Indent(4), VTK::Precision::int32); +#endif for (size_t i=0; i<cellOffsets_.size(); i++) cellOffsetsWriter.write(cellOffsets_[i]); } { // extra parenthesis to control destruction of the writer object +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) Dune::VTK::AsciiDataArrayWriter<unsigned int> cellTypesWriter(outFile, "types", 1, Dune::Indent(4)); +#else + Dune::VTK::AsciiDataArrayWriter cellTypesWriter(outFile, "types", 1, Dune::Indent(4), VTK::Precision::uint32); +#endif for (size_t i=0; i<cellTypes_.size(); i++) cellTypesWriter.write(cellTypes_[i]); } @@ -124,7 +156,11 @@ namespace Dune { // Z coordinate for better visualization of wrinkles { // extra parenthesis to control destruction of the writer object +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) Dune::VTK::AsciiDataArrayWriter<float> zCoordWriter(outFile, "zCoord", 1, Dune::Indent(4)); +#else + Dune::VTK::AsciiDataArrayWriter zCoordWriter(outFile, "zCoord", 1, Dune::Indent(4), VTK::Precision::float32); +#endif for (size_t i=0; i<zCoord_.size(); i++) zCoordWriter.write(zCoord_[i]); } @@ -132,7 +168,11 @@ namespace Dune { // The three director fields for (size_t i=0; i<3; i++) { +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) Dune::VTK::AsciiDataArrayWriter<float> directorWriter(outFile, "director" + std::to_string(i), 3, Dune::Indent(4)); +#else + Dune::VTK::AsciiDataArrayWriter directorWriter(outFile, "director" + std::to_string(i), 3, Dune::Indent(4), VTK::Precision::float32); +#endif for (size_t j=0; j<directors_[i].size(); j++) for (int k=0; k<3; k++) directorWriter.write(directors_[i][j][k]); @@ -148,7 +188,11 @@ namespace Dune { { outFile << " <CellData>" << std::endl; { // extra parenthesis to control destruction of the writer object +#if DUNE_VERSION_LT(DUNE_FUNCTIONS,2,7) Dune::VTK::AsciiDataArrayWriter<float> cellDataWriter(outFile, "mycelldata", 1, Dune::Indent(4)); +#else + Dune::VTK::AsciiDataArrayWriter cellDataWriter(outFile, "mycelldata", 1, Dune::Indent(4), VTK::Precision::float32); +#endif for (size_t i=0; i<cellData_.size(); i++) cellDataWriter.write(cellData_[i]); } diff --git a/dune/gfe/vtkreader.hh b/dune/gfe/vtkreader.hh index 566deead39a87ad62ed886dadd5c153921f5ab04..1279a655e0233f591cd881ff1aaf0e04bb903447 100644 --- a/dune/gfe/vtkreader.hh +++ b/dune/gfe/vtkreader.hh @@ -35,12 +35,9 @@ public: factory.insertVertex(pos); } - Dune::GeometryType triangle; - triangle.makeTriangle(); - for (size_t i=0; i<vtkFile.cellConnectivity_.size(); i+=3) { - factory.insertElement(triangle, {vtkFile.cellConnectivity_[i], + factory.insertElement(Dune::GeometryTypes::triangle, {vtkFile.cellConnectivity_[i], vtkFile.cellConnectivity_[i+1], vtkFile.cellConnectivity_[i+2]}); @@ -51,4 +48,4 @@ public: }; -#endif \ No newline at end of file +#endif diff --git a/problems/cantilever-dirichlet-values.py b/problems/cantilever-dirichlet-values.py new file mode 100644 index 0000000000000000000000000000000000000000..0d1d60a5c0b33499677be2da2c10d2e6ea91b17c --- /dev/null +++ b/problems/cantilever-dirichlet-values.py @@ -0,0 +1,17 @@ +import math + +class DirichletValues: + def __init__(self, homotopyParameter): + self.homotopyParameter = homotopyParameter + + def deformation(self, x): + # Dirichlet b.c. simply clamp the shell in the reference configuration + out = [x[0], x[1], 0] + + return out + + + def orientation(self, x): + rotation = [[1,0,0], [0, 1, 0], [0, 0, 1]] + return rotation + diff --git a/problems/cosserat-continuum-cantilever.parset b/problems/cosserat-continuum-cantilever.parset new file mode 100644 index 0000000000000000000000000000000000000000..4244121458e5add3ca49043149afe4c7340eb6f8 --- /dev/null +++ b/problems/cosserat-continuum-cantilever.parset @@ -0,0 +1,110 @@ +############################################# +# Grid parameters +############################################# + +structuredGrid = true + +# bounding box +lower = 0 0 +upper = 100 10 + +elements = 10 1 + +# Number of grid levels +numLevels = 1 + +############################################# +# Solver parameters +############################################# + +# Number of homotopy steps for the Dirichlet boundary conditions +numHomotopySteps = 1 + +# Tolerance of the trust region solver +tolerance = 1e-3 + +# Max number of steps of the trust region solver +maxTrustRegionSteps = 200 + +trustRegionScaling = 1 1 1 0.01 0.01 0.01 + +# Initial trust-region radius +initialTrustRegionRadius = 3.125 + +# Number of multigrid iterations per trust-region step +numIt = 400 + +# Number of presmoothing steps +nu1 = 3 + +# Number of postsmoothing steps +nu2 = 3 + +# Number of coarse grid corrections +mu = 1 + +# Number of base solver iterations +baseIt = 1 + +# Tolerance of the multigrid solver +mgTolerance = 1e-5 + +# Tolerance of the base grid solver +baseTolerance = 1e-8 + +# Measure convergence +instrumented = 0 + +############################ +# Material parameters +############################ + + +## For the Wriggers L-shape example +[materialParameters] + +# shell thickness +thickness = 0.6 + +# Lame parameters +# corresponds to E = 71240 N/mm^2, nu=0.31 +# However, we use units N/m^2 +mu = 2.7191e+4 +lambda = 4.4364e+4 + +# Cosserat couple modulus +mu_c = 0 + +# Length scale parameter +L_c = 0.6 + +# Curvature exponent +q = 2 + +# Shear correction factor +kappa = 1 + +[] + +############################################# +# Boundary values +############################################# + +problem = cantilever + +### Python predicate specifying all Dirichlet grid vertices +# x is the vertex coordinate +dirichletVerticesPredicate = "x[0] < 0.01" + +### Python predicate specifying all Neumann grid vertices +# x is the vertex coordinate +neumannVerticesPredicate = "x[0] > 99.99" + +### Neumann values +neumannValues = 0 0 3 + +# Initial deformation +initialDeformation = "[x[0], x[1], 0]" + +#startFromFile = yes +#initialIterateFilename = initial_iterate.vtu diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d0e141f0357ba9068d2f0b7a1c355d71c58392d7..45a09e9929fa2e21f5abe2511d677218954de0e0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,16 +2,13 @@ set(programs compute-disc-error cosserat-continuum gradient-flow harmonicmaps - mixed-cosserat-continuum rod-eoc) # rodobstacle) foreach(_program ${programs}) add_executable(${_program} ${_program}.cc) - add_dune_adolc_flags(${_program}) - add_dune_ipopt_flags(${_program}) + target_link_dune_default_libraries(${_program}) add_dune_pythonlibs_flags(${_program}) - add_dune_ug_flags(${_program}) - add_dune_mpi_flags(${_program}) + target_link_libraries(${_program} tinyxml2) # target_compile_options(${_program} PRIVATE "-fpermissive") endforeach() diff --git a/src/compute-disc-error.cc b/src/compute-disc-error.cc index 14b9551f3514ea19cff4a9ca4b97eb3c71b04dd4..97cabf4093320723277103a98e7a3bd3fc21e26c 100644 --- a/src/compute-disc-error.cc +++ b/src/compute-disc-error.cc @@ -6,15 +6,23 @@ #include <dune/common/parametertreeparser.hh> #include <dune/grid/uggrid.hh> +#include <dune/grid/common/mcmgmapper.hh> #include <dune/grid/io/file/gmshreader.hh> #include <dune/grid/utility/structuredgridfactory.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#if HAVE_DUNE_FOAMGRID +#include <dune/foamgrid/foamgrid.hh> +#else +#include <dune/grid/onedgrid.hh> +#endif + +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/matrix-vector/genericvectortools.hh> #include <dune/fufem/discretizationerror.hh> #include <dune/fufem/dunepython.hh> +#include <dune/fufem/makesphere.hh> #include <dune/gfe/rotation.hh> #include <dune/gfe/unitvector.hh> @@ -29,6 +37,116 @@ const int dimworld = 2; using namespace Dune; +/** \brief Check whether given local coordinates are contained in the reference element + \todo This method exists in the Dune grid interface! But we need the eps. +*/ +static bool checkInside(const Dune::GeometryType& type, + const Dune::FieldVector<double, dim> &loc, + double eps) +{ + switch (type.dim()) + { + case 0: // vertex + return false; + + case 1: // line + return -eps <= loc[0] && loc[0] <= 1+eps; + + case 2: + + if (type.isSimplex()) { + return -eps <= loc[0] && -eps <= loc[1] && (loc[0]+loc[1])<=1+eps; + } else if (type.isCube()) { + return -eps <= loc[0] && loc[0] <= 1+eps + && -eps <= loc[1] && loc[1] <= 1+eps; + } else + DUNE_THROW(Dune::GridError, "checkInside(): ERROR: Unknown type " << type << " found!"); + + case 3: + if (type.isSimplex()) { + return -eps <= loc[0] && -eps <= loc[1] && -eps <= loc[2] + && (loc[0]+loc[1]+loc[2]) <= 1+eps; + } else if (type.isPyramid()) { + return -eps <= loc[0] && -eps <= loc[1] && -eps <= loc[2] + && (loc[0]+loc[2]) <= 1+eps + && (loc[1]+loc[2]) <= 1+eps; + } else if (type.isPrism()) { + return -eps <= loc[0] && -eps <= loc[1] + && (loc[0]+loc[1])<= 1+eps + && -eps <= loc[2] && loc[2] <= 1+eps; + } else if (type.isCube()) { + return -eps <= loc[0] && loc[0] <= 1+eps + && -eps <= loc[1] && loc[1] <= 1+eps + && -eps <= loc[2] && loc[2] <= 1+eps; + }else + DUNE_THROW(Dune::GridError, "checkInside(): ERROR: Unknown type " << type << " found!"); + + default: + DUNE_THROW(Dune::GridError, "checkInside(): ERROR: Unknown type " << type << " found!"); + } + +} + +/** \param element An element of the source grid + */ +template <class GridType> +auto findSupportingElement(const GridType& sourceGrid, + const GridType& targetGrid, + typename GridType::template Codim<0>::Entity element, + FieldVector<double,dim> pos) +{ + while (element.level() != 0) + { + pos = element.geometryInFather().global(pos); + element = element.father(); + + assert(checkInside(element.type(), pos, 1e-7)); + } + + ////////////////////////////////////////////////////////////////////// + // Find the corresponding coarse grid element on the adaptive grid. + // This is a linear algorithm, but we expect the coarse grid to be small. + ////////////////////////////////////////////////////////////////////// + LevelMultipleCodimMultipleGeomTypeMapper<GridType> sourceP0Mapper (sourceGrid, 0, mcmgElementLayout()); + LevelMultipleCodimMultipleGeomTypeMapper<GridType> targetP0Mapper(targetGrid, 0, mcmgElementLayout()); + const auto coarseIndex = sourceP0Mapper.index(element); + + auto targetLevelView = targetGrid.levelGridView(0); + + for (auto&& targetElement : elements(targetLevelView)) + if (targetP0Mapper.index(targetElement) == coarseIndex) + { + element = std::move(targetElement); + break; + } + + ////////////////////////////////////////////////////////////////////////// + // Find a corresponding point (not necessarily vertex) on the leaf level + // of the adaptive grid. + ////////////////////////////////////////////////////////////////////////// + + while (!element.isLeaf()) + { + FieldVector<double,dim> childPos; + assert(checkInside(element.type(), pos, 1e-7)); + + auto hIt = element.hbegin(element.level()+1); + auto hEndIt = element.hend(element.level()+1); + + for (; hIt!=hEndIt; ++hIt) + { + childPos = hIt->geometryInFather().local(pos); + if (checkInside(hIt->type(), childPos, 1e-7)) + break; + } + + element = *hIt; + pos = childPos; + } + + return std::tie(element, pos); +} + template <class GridView, int order, class TargetSpace> void measureDiscreteEOC(const GridView gridView, const GridView referenceGridView, @@ -40,7 +158,7 @@ void measureDiscreteEOC(const GridView gridView, // Construct the scalar function space bases corresponding to the GFE space ////////////////////////////////////////////////////////////////////////////////// - typedef Dune::Functions::PQkNodalBasis<GridView, order> FEBasis; + typedef Dune::Functions::LagrangeBasis<GridView, order> FEBasis; FEBasis feBasis(gridView); FEBasis referenceFEBasis(referenceGridView); @@ -121,23 +239,54 @@ void measureDiscreteEOC(const GridView gridView, auto element = hierarchicSearch.findEntity(globalPos); auto localPos = element.geometry().local(globalPos); - auto diff = referenceSolution(rElement, qp.position()) - numericalSolution(element, localPos); + auto refValue = referenceSolution(rElement, qp.position()); + auto numValue = numericalSolution(element, localPos); + auto diff = refValue - numValue; assert(diff.size()==7); + // Compute error of the displacement degrees of freedom for (int i=0; i<3; i++) deformationL2ErrorSquared += integrationElement * qp.weight() * diff[i] * diff[i]; - for (int i=3; i<7; i++) - orientationL2ErrorSquared += integrationElement * qp.weight() * diff[i] * diff[i]; - auto derDiff = referenceSolution.derivative(rElement, qp.position()) - numericalSolution.derivative(element, localPos); for (int i=0; i<3; i++) deformationH1ErrorSquared += integrationElement * qp.weight() * derDiff[i].two_norm2(); - for (int i=3; i<7; i++) - orientationH1ErrorSquared += integrationElement * qp.weight() * derDiff[i].two_norm2(); + // Compute error of the orientation degrees of freedom + // We need to transform from quaternion coordinates to matrix coordinates first. + FieldMatrix<double,3,3> referenceValue, numericalValue; + Rotation<double,3> referenceRotation(std::array<double,4>{refValue[3], refValue[4], refValue[5], refValue[6]}); + referenceRotation.matrix(referenceValue); + + Rotation<double,3> numericalRotation(std::array<double,4>{numValue[3], numValue[4], numValue[5], numValue[6]}); + numericalRotation.matrix(numericalValue); + auto orientationDiff = referenceValue - numericalValue; + + orientationL2ErrorSquared += integrationElement * qp.weight() * orientationDiff.frobenius_norm2(); + + auto referenceDerQuat = referenceSolution.derivative(rElement, qp.position()); + auto numericalDerQuat = numericalSolution.derivative(element, localPos); + + // Transform to matrix coordinates + Tensor3<double,3,3,4> derivativeQuaternionToMatrixRef = Rotation<double,3>::derivativeOfQuaternionToMatrix(FieldVector<double,4>{refValue[3], refValue[4], refValue[5], refValue[6]}); + Tensor3<double,3,3,4> derivativeQuaternionToMatrixNum = Rotation<double,3>::derivativeOfQuaternionToMatrix(FieldVector<double,4>{numValue[3], numValue[4], numValue[5], numValue[6]}); + + Tensor3<double,3,3,dim> refDerivative(0); + Tensor3<double,3,3,dim> numDerivative(0); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<dim; k++) + for (int l=0; l<4; l++) + { + refDerivative[i][j][k] += derivativeQuaternionToMatrixRef[i][j][l] * referenceDerQuat[3+l][k]; + numDerivative[i][j][k] += derivativeQuaternionToMatrixNum[i][j][l] * numericalDerQuat[3+l][k]; + } + + auto derOrientationDiff = refDerivative - numDerivative; // compute the difference + orientationH1ErrorSquared += derOrientationDiff.frobenius_norm2() * qp.weight() * integrationElement; } } @@ -152,6 +301,69 @@ void measureDiscreteEOC(const GridView gridView, << "H^1 error orientation: " << std::sqrt(orientationH1ErrorSquared) << std::endl; } + else if constexpr (std::is_same<TargetSpace,Rotation<double,3> >::value) + { + double l2ErrorSquared = 0; + double h1ErrorSquared = 0; + + for (const auto& rElement : elements(referenceGridView)) + { + const auto& quadRule = QuadratureRules<double, dim>::rule(rElement.type(), 6); + + for (const auto& qp : quadRule) + { + auto integrationElement = rElement.geometry().integrationElement(qp.position()); + + auto globalPos = rElement.geometry().global(qp.position()); + + auto element = hierarchicSearch.findEntity(globalPos); + auto localPos = element.geometry().local(globalPos); + + FieldMatrix<double,3,3> referenceValue, numericalValue; + auto refValue = referenceSolution(rElement, qp.position()); + Rotation<double,3> referenceRotation(refValue); + referenceRotation.matrix(referenceValue); + + auto numValue = numericalSolution(element, localPos); + Rotation<double,3> numericalRotation(numValue); + numericalRotation.matrix(numericalValue); + + auto diff = referenceValue - numericalValue; + + l2ErrorSquared += integrationElement * qp.weight() * diff.frobenius_norm2(); + + auto referenceDerQuat = referenceSolution.derivative(rElement, qp.position()); + auto numericalDerQuat = numericalSolution.derivative(element, localPos); + + // Transform to matrix coordinates + Tensor3<double,3,3,4> derivativeQuaternionToMatrixRef = Rotation<double,3>::derivativeOfQuaternionToMatrix(refValue); + Tensor3<double,3,3,4> derivativeQuaternionToMatrixNum = Rotation<double,3>::derivativeOfQuaternionToMatrix(numValue); + + Tensor3<double,3,3,dim> refDerivative(0); + Tensor3<double,3,3,dim> numDerivative(0); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<dim; k++) + for (int l=0; l<4; l++) + { + refDerivative[i][j][k] += derivativeQuaternionToMatrixRef[i][j][l] * referenceDerQuat[l][k]; + numDerivative[i][j][k] += derivativeQuaternionToMatrixNum[i][j][l] * numericalDerQuat[l][k]; + } + + auto derDiff = refDerivative - numDerivative; // compute the difference + h1ErrorSquared += derDiff.frobenius_norm2() * qp.weight() * integrationElement; + + } + } + + std::cout << "levels: " << gridView.grid().maxLevel()+1 + << " " + << "L^2 error: " << std::sqrt(l2ErrorSquared) + << " " + << "h^1 error: " << std::sqrt(h1ErrorSquared) + << std::endl; + } else { double l2ErrorSquared = 0; @@ -165,10 +377,13 @@ void measureDiscreteEOC(const GridView gridView, { auto integrationElement = rElement.geometry().integrationElement(qp.position()); - auto globalPos = rElement.geometry().global(qp.position()); - - auto element = hierarchicSearch.findEntity(globalPos); - auto localPos = element.geometry().local(globalPos); + // Given a point with local coordinates qp.position() on element rElement of the reference grid + // find the element and local coordinates on the grid of the numerical simulation + auto supportingElement = findSupportingElement(referenceGridView.grid(), + gridView.grid(), + rElement, qp.position()); + auto element = std::get<0>(supportingElement); + auto localPos = std::get<1>(supportingElement); auto diff = referenceSolution(rElement, qp.position()) - numericalSolution(element, localPos); @@ -200,7 +415,7 @@ void measureAnalyticalEOC(const GridView gridView, // Construct the scalar function space bases corresponding to the GFE space ////////////////////////////////////////////////////////////////////////////////// - typedef Dune::Functions::PQkNodalBasis<GridView, order> FEBasis; + typedef Dune::Functions::LagrangeBasis<GridView, order> FEBasis; FEBasis feBasis(gridView); ////////////////////////////////////////////////////////////////////////////////// @@ -229,7 +444,7 @@ void measureAnalyticalEOC(const GridView gridView, ///////////////////////////////////////////////////////////////// // Read reference solution and its derivative into a PythonFunction - typedef VirtualDifferentiableFunction<FieldVector<double, dim>, typename TargetSpace::CoordinateType> FBase; + typedef VirtualDifferentiableFunction<FieldVector<double, dimworld>, typename TargetSpace::CoordinateType> FBase; Python::Module module = Python::import(parameterSet.get<std::string>("referenceSolution")); auto referenceSolution = module.get("fdf").toC<std::shared_ptr<FBase>>(); @@ -250,22 +465,116 @@ void measureAnalyticalEOC(const GridView gridView, // QuadratureRule for the integral of the L^2 error QuadratureRuleKey quadKey(dim,6); - // Compute the embedded L^2 error - double l2Error = DiscretizationError<GridView>::computeL2Error(numericalSolution.get(), - referenceSolution.get(), - quadKey); + // Compute errors in the L2 norm and the h1 seminorm. + // SO(3)-valued maps need special treatment, because they are stored as quaternions, + // but the errors need to be computed in matrix space. + if constexpr (std::is_same<TargetSpace,Rotation<double,3> >::value) + { + constexpr int blocksize = TargetSpace::CoordinateType::dimension; - // Compute the embedded H^1 error - double h1Error = DiscretizationError<GridView>::computeH1HalfNormDifferenceSquared(gridView, - numericalSolution.get(), - referenceSolution.get(), - quadKey); + // The error to be computed + double l2ErrorSquared = 0; + double h1ErrorSquared = 0; - std::cout << "elements: " << gridView.size(0) - << " " - << "L^2 error: " << l2Error - << " "; - std::cout << "h^1 error: " << std::sqrt(h1Error) << std::endl; + for (auto&& element : elements(gridView)) + { + // Get quadrature formula + quadKey.setGeometryType(element.type()); + const auto& quad = QuadratureRuleCache<double, dim>::rule(quadKey); + + for (auto quadPoint : quad) + { + auto quadPos = quadPoint.position(); + const auto integrationElement = element.geometry().integrationElement(quadPos); + const auto weight = quadPoint.weight(); + + // Evaluate function a + FieldVector<double,blocksize> numValue; + numericalSolution.get()->evaluateLocal(element, quadPos,numValue); + + // Evaluate function b. If it is a grid function use that to speed up the evaluation + FieldVector<double,blocksize> refValue; + if (std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)) + std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)->evaluateLocal(element, + quadPos, + refValue + ); + else + referenceSolution->evaluate(element.geometry().global(quadPos), refValue); + + // Get error in matrix space + Rotation<double,3> numRotation(numValue); + FieldMatrix<double,3,3> numValueMatrix; + numRotation.matrix(numValueMatrix); + + Rotation<double,3> refRotation(refValue); + FieldMatrix<double,3,3> refValueMatrix; + refRotation.matrix(refValueMatrix); + + // Evaluate derivatives in quaternion space + FieldMatrix<double,blocksize,dimworld> num_di; + FieldMatrix<double,blocksize,dimworld> ref_di; + + if (dynamic_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >*>(numericalSolution.get())) + dynamic_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >*>(numericalSolution.get())->evaluateDerivativeLocal(element, + quadPos, + num_di); + else + numericalSolution->evaluateDerivative(element.geometry().global(quadPos), num_di); + + if (std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)) + std::dynamic_pointer_cast<const VirtualGridViewFunction<GridView,FieldVector<double,blocksize> >>(referenceSolution)->evaluateDerivativeLocal(element, + quadPos, + ref_di); + else + referenceSolution->evaluateDerivative(element.geometry().global(quadPos), ref_di); + + // Transform into matrix space + Tensor3<double,3,3,4> derivativeQuaternionToMatrixNum = Rotation<double,3>::derivativeOfQuaternionToMatrix(numValue); + Tensor3<double,3,3,4> derivativeQuaternionToMatrixRef = Rotation<double,3>::derivativeOfQuaternionToMatrix(refValue); + + Tensor3<double,3,3,dim> numDerivative(0); + Tensor3<double,3,3,dim> refDerivative(0); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + for (int k=0; k<dim; k++) + for (int l=0; l<blocksize; l++) + { + numDerivative[i][j][k] += derivativeQuaternionToMatrixNum[i][j][l] * num_di[l][k]; + refDerivative[i][j][k] += derivativeQuaternionToMatrixRef[i][j][l] * ref_di[l][k]; + } + + // integrate error + l2ErrorSquared += (numValueMatrix - refValueMatrix).frobenius_norm2() * weight * integrationElement; + auto diff = numDerivative - refDerivative; + h1ErrorSquared += diff.frobenius_norm2() * weight * integrationElement; + } + } + + std::cout << "elements: " << gridView.size(0) + << " " + << "L^2 error: " << std::sqrt(l2ErrorSquared) + << " "; + std::cout << "h^1 error: " << std::sqrt(h1ErrorSquared) << std::endl; + } + else + { + auto l2Error = DiscretizationError<GridView>::computeL2Error(numericalSolution.get(), + referenceSolution.get(), + quadKey); + + auto h1Error = DiscretizationError<GridView>::computeH1HalfNormDifferenceSquared(gridView, + numericalSolution.get(), + referenceSolution.get(), + quadKey); + + std::cout << "elements: " << gridView.size(0) + << " " + << "L^2 error: " << l2Error + << " "; + std::cout << "h^1 error: " << std::sqrt(h1Error) << std::endl; + } } template <class GridType, class TargetSpace> @@ -277,6 +586,8 @@ void measureEOC(const std::shared_ptr<GridType> grid, if (parameterSet.get<std::string>("discretizationErrorMode")=="discrete") { + referenceGrid->globalRefine(parameterSet.get<int>("numReferenceLevels")-1); + switch (order) { case 1: @@ -294,6 +605,7 @@ void measureEOC(const std::shared_ptr<GridType> grid, default: DUNE_THROW(NotImplemented, "Order '" << order << "' is not implemented"); } + return; // Success } if (parameterSet.get<std::string>("discretizationErrorMode")=="analytical") @@ -315,7 +627,10 @@ void measureEOC(const std::shared_ptr<GridType> grid, default: DUNE_THROW(NotImplemented, "Order '" << order << "' is not implemented"); } + return; // Success } + + DUNE_THROW(NotImplemented, "Unknown discretization error mode encountered!"); } int main (int argc, char *argv[]) try @@ -347,7 +662,12 @@ int main (int argc, char *argv[]) try ///////////////////////////////////////// // Create the grids ///////////////////////////////////////// - typedef UGGrid<dim> GridType; +#if HAVE_DUNE_FOAMGRID + typedef std::conditional<dim==1 or dim!=dimworld,FoamGrid<dim,dimworld>,UGGrid<dim> >::type GridType; +#else + static_assert(dim==dimworld, "You need to have dune-foamgrid installed for dim != dimworld!"); + typedef std::conditional<dim==1,OneDGrid,UGGrid<dim> >::type GridType; +#endif const int numLevels = parameterSet.get<int>("numLevels"); @@ -356,29 +676,41 @@ int main (int argc, char *argv[]) try FieldVector<double,dimworld> lower(0), upper(1); std::string structuredGridType = parameterSet["structuredGrid"]; - if (structuredGridType != "false" ) + if (structuredGridType == "sphere") + { + if constexpr (dimworld==3) + { + grid = makeSphereOnOctahedron<GridType>({0,0,0},1); + referenceGrid = makeSphereOnOctahedron<GridType>({0,0,0},1); + } else + DUNE_THROW(Exception, "Dimworld must be 3 to create a sphere grid!"); + } + else if (structuredGridType == "simplex" || structuredGridType == "cube") { lower = parameterSet.get<FieldVector<double,dimworld> >("lower"); upper = parameterSet.get<FieldVector<double,dimworld> >("upper"); auto elements = parameterSet.get<std::array<unsigned int,dim> >("elements"); if (structuredGridType == "simplex") - grid = StructuredGridFactory<GridType>::createSimplexGrid(lower, upper, elements); - else if (structuredGridType == "cube") - grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements); - else + { + grid = StructuredGridFactory<GridType>::createSimplexGrid(lower, upper, elements); + referenceGrid = StructuredGridFactory<GridType>::createSimplexGrid(lower, upper, elements); + } else if (structuredGridType == "cube") + { + grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements); + referenceGrid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements); + } else DUNE_THROW(Exception, "Unknown structured grid type '" << structuredGridType << "' found!"); } else { std::string path = parameterSet.get<std::string>("path"); std::string gridFile = parameterSet.get<std::string>("gridFile"); - grid = shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile)); + grid = shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile)); referenceGrid = shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile)); } grid->globalRefine(numLevels-1); - referenceGrid->globalRefine(parameterSet.get<int>("numReferenceLevels")-1); // Do the actual measurement const int targetDim = parameterSet.get<int>("targetDim"); @@ -486,7 +818,7 @@ int main (int argc, char *argv[]) try return 0; } -catch (Exception e) +catch (Exception& e) { std::cout << e << std::endl; return 1; diff --git a/src/cosserat-continuum.cc b/src/cosserat-continuum.cc index 95c87570a740a9e0c545281a52180cd5d9d5391c..9029c25248891d0c0e8614d1eca0ad72de6c7911 100644 --- a/src/cosserat-continuum.cc +++ b/src/cosserat-continuum.cc @@ -1,6 +1,7 @@ #include <config.h> #include <fenv.h> +#include <array> // Includes for the ADOL-C automatic differentiation library // Need to come before (almost) all others. @@ -10,9 +11,11 @@ #include <dune/fufem/utilities/adolcnamespaceinjections.hh> +#include <dune/common/typetraits.hh> #include <dune/common/bitsetvector.hh> #include <dune/common/parametertree.hh> #include <dune/common/parametertreeparser.hh> +#include <dune/common/tuplevector.hh> #include <dune/grid/uggrid.hh> #include <dune/grid/utility/structuredgridfactory.hh> @@ -23,7 +26,9 @@ #include <dune/foamgrid/foamgrid.hh> #endif -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> +#include <dune/functions/functionspacebases/compositebasis.hh> +#include <dune/functions/functionspacebases/powerbasis.hh> #include <dune/fufem/boundarypatch.hh> #include <dune/fufem/functiontools/boundarydofs.hh> @@ -36,6 +41,7 @@ #include <dune/gfe/rigidbodymotion.hh> #include <dune/gfe/localgeodesicfeadolcstiffness.hh> +#include <dune/gfe/mixedlocalgfeadolcstiffness.hh> #include <dune/gfe/cosseratenergystiffness.hh> #include <dune/gfe/nonplanarcosseratshellenergy.hh> #include <dune/gfe/cosseratvtkwriter.hh> @@ -45,19 +51,30 @@ #include <dune/gfe/riemanniantrsolver.hh> #include <dune/gfe/vertexnormals.hh> #include <dune/gfe/embeddedglobalgfefunction.hh> +#include <dune/gfe/mixedgfeassembler.hh> +#include <dune/gfe/mixedriemanniantrsolver.hh> // grid dimension const int dim = 2; const int dimworld = 2; -// Order of the approximation space -const int order = 2; +//#define MIXED_SPACE + +// Order of the approximation space for the displacement +const int displacementOrder = 2; + +// Order of the approximation space for the microrotations +const int rotationOrder = 2; + +#ifndef MIXED_SPACE +static_assert(displacementOrder==rotationOrder, "displacement and rotation order do not match!"); // Image space of the geodesic fe functions typedef RigidBodyMotion<double,3> TargetSpace; // Tangent vector of the image space const int blocksize = TargetSpace::TangentVector::dimension; +#endif using namespace Dune; @@ -116,7 +133,13 @@ int main (int argc, char *argv[]) try << std::endl << "sys.path.append('/home/sander/dune/dune-gfe/problems/')" << std::endl; + using namespace TypeTree::Indices; +#ifdef MIXED_SPACE + using SolutionType = TupleVector<std::vector<RealTuple<double,3> >, + std::vector<Rotation<double,3> > >; +#else typedef std::vector<TargetSpace> SolutionType; +#endif // parse data file ParameterTree parameterSet; @@ -157,12 +180,13 @@ int main (int argc, char *argv[]) try FieldVector<double,dimworld> lower(0), upper(1); - if (parameterSet.get<bool>("structuredGrid")) { + std::string structuredGridType = parameterSet["structuredGrid"]; + if (structuredGridType == "cube") { lower = parameterSet.get<FieldVector<double,dimworld> >("lower"); upper = parameterSet.get<FieldVector<double,dimworld> >("upper"); - array<unsigned int,dim> elements = parameterSet.get<array<unsigned int,dim> >("elements"); + auto elements = parameterSet.get<std::array<unsigned int,dim> >("elements"); grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements); } else { @@ -191,11 +215,35 @@ int main (int argc, char *argv[]) try typedef GridType::LeafGridView GridView; GridView gridView = grid->leafGridView(); - typedef Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView, order> FEBasis; + using namespace Dune::Functions::BasisFactory; +#ifdef MIXED_SPACE + auto compositeBasis = makeBasis( + gridView, + composite( + lagrange<displacementOrder>(), + lagrange<rotationOrder>() + ) + ); + + typedef Dune::Functions::LagrangeBasis<GridView,displacementOrder> DeformationFEBasis; + typedef Dune::Functions::LagrangeBasis<GridView,rotationOrder> OrientationFEBasis; + + DeformationFEBasis deformationFEBasis(gridView); + OrientationFEBasis orientationFEBasis(gridView); + + // Construct fufem-style function space bases to ease the transition to dune-functions + typedef DuneFunctionsBasis<DeformationFEBasis> FufemDeformationFEBasis; + FufemDeformationFEBasis fufemDeformationFEBasis(deformationFEBasis); + + typedef DuneFunctionsBasis<OrientationFEBasis> FufemOrientationFEBasis; + FufemOrientationFEBasis fufemOrientationFEBasis(orientationFEBasis); +#else + typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView, displacementOrder> FEBasis; FEBasis feBasis(gridView); typedef DuneFunctionsBasis<FEBasis> FufemFEBasis; FufemFEBasis fufemFeBasis(feBasis); +#endif // ///////////////////////////////////////// // Read Dirichlet values @@ -232,23 +280,71 @@ int main (int argc, char *argv[]) try if (mpiHelper.rank()==0) std::cout << "Neumann boundary has " << neumannBoundary.numFaces() << " faces\n"; +#ifdef MIXED_SPACE + BitSetVector<1> deformationDirichletNodes(deformationFEBasis.size(), false); + constructBoundaryDofs(dirichletBoundary,fufemDeformationFEBasis,deformationDirichletNodes); - BitSetVector<1> dirichletNodes(feBasis.indexSet().size(), false); - constructBoundaryDofs(dirichletBoundary,fufemFeBasis,dirichletNodes); + BitSetVector<1> neumannNodes(deformationFEBasis.size(), false); + constructBoundaryDofs(neumannBoundary,fufemDeformationFEBasis,neumannNodes); + + BitSetVector<3> deformationDirichletDofs(deformationFEBasis.size(), false); + for (size_t i=0; i<deformationFEBasis.size(); i++) + if (deformationDirichletNodes[i][0]) + for (int j=0; j<3; j++) + deformationDirichletDofs[i][j] = true; + + BitSetVector<1> orientationDirichletNodes(orientationFEBasis.size(), false); + constructBoundaryDofs(dirichletBoundary,fufemOrientationFEBasis,orientationDirichletNodes); + + BitSetVector<3> orientationDirichletDofs(orientationFEBasis.size(), false); + for (size_t i=0; i<orientationFEBasis.size(); i++) + if (orientationDirichletNodes[i][0]) + for (int j=0; j<3; j++) + orientationDirichletDofs[i][j] = true; +#else + BitSetVector<1> dirichletNodes(feBasis.size(), false); + constructBoundaryDofs(dirichletBoundary,feBasis,dirichletNodes); - BitSetVector<1> neumannNodes(feBasis.indexSet().size(), false); - constructBoundaryDofs(neumannBoundary,fufemFeBasis,neumannNodes); + BitSetVector<1> neumannNodes(feBasis.size(), false); + constructBoundaryDofs(neumannBoundary,feBasis,neumannNodes); - BitSetVector<blocksize> dirichletDofs(feBasis.indexSet().size(), false); - for (size_t i=0; i<feBasis.indexSet().size(); i++) + BitSetVector<blocksize> dirichletDofs(feBasis.size(), false); + for (size_t i=0; i<feBasis.size(); i++) if (dirichletNodes[i][0]) for (int j=0; j<5; j++) dirichletDofs[i][j] = true; +#endif // ////////////////////////// // Initial iterate // ////////////////////////// +#ifdef MIXED_SPACE + SolutionType x; + + x[_0].resize(deformationFEBasis.size()); + + lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")"); + PythonFunction<FieldVector<double,dim>, FieldVector<double,3> > pythonInitialDeformation(Python::evaluate(lambda)); + + std::vector<FieldVector<double,3> > v; + ::Functions::interpolate(fufemDeformationFEBasis, v, pythonInitialDeformation); + + for (size_t i=0; i<x[_0].size(); i++) + x[_0][i] = v[i]; + + x[_1].resize(orientationFEBasis.size()); +#if 0 + lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")"); + PythonFunction<FieldVector<double,dim>, FieldVector<double,3> > pythonInitialDeformation(Python::evaluate(lambda)); + + std::vector<FieldVector<double,3> > v; + Functions::interpolate(feBasis, v, pythonInitialDeformation); + + for (size_t i=0; i<x.size(); i++) + xDisp[i] = v[i]; +#endif +#else SolutionType x(feBasis.size()); if (parameterSet.hasKey("startFromFile")) @@ -256,7 +352,7 @@ int main (int argc, char *argv[]) try std::shared_ptr<GridType> initialIterateGrid; if (parameterSet.get<bool>("structuredGrid")) { - std::array<unsigned int,dim> elements = parameterSet.get<array<unsigned int,dim> >("elements"); + std::array<unsigned int,dim> elements = parameterSet.get<std::array<unsigned int,dim> >("elements"); initialIterateGrid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements); } else @@ -270,13 +366,19 @@ int main (int argc, char *argv[]) try SolutionType initialIterate; GFE::CosseratVTKReader::read(initialIterate, parameterSet.get<std::string>("initialIterateFilename")); - typedef Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView, 2> InitialBasis; + typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView, 2> InitialBasis; InitialBasis initialBasis(initialIterateGrid->leafGridView()); - GFE::EmbeddedGlobalGFEFunction<InitialBasis,TargetSpace> initialFunction(initialBasis,initialIterate); +#ifdef PROJECTED_INTERPOLATION + using LocalInterpolationRule = LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace>; +#else + using LocalInterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace>; +#endif + GFE::EmbeddedGlobalGFEFunction<InitialBasis,LocalInterpolationRule,TargetSpace> initialFunction(initialBasis,initialIterate); std::vector<FieldVector<double,7> > v; Dune::Functions::interpolate(feBasis,v,initialFunction); + DUNE_THROW(NotImplemented, "Replace scalar basis by power basis!"); for (size_t i=0; i<x.size(); i++) x[i] = TargetSpace(v[i]); @@ -291,13 +393,20 @@ int main (int argc, char *argv[]) try for (size_t i=0; i<x.size(); i++) x[i].r = v[i]; } +#endif //////////////////////////////////////////////////////// // Main homotopy loop //////////////////////////////////////////////////////// // Output initial iterate (of homotopy loop) +#ifdef MIXED_SPACE + CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,x[_0], + orientationFEBasis,x[_1], + resultPath + "mixed-cosserat_homotopy_0"); +#else CosseratVTKWriter<GridType>::write<FEBasis>(feBasis,x, resultPath + "cosserat_homotopy_0"); +#endif for (int i=0; i<numHomotopySteps; i++) { @@ -316,17 +425,32 @@ int main (int argc, char *argv[]) try neumannFunction = make_shared<NeumannFunction>(parameterSet.get<FieldVector<double,3> >("neumannValues"), homotopyParameter); - shared_ptr<VolumeLoad> volumeLoad; - if (parameterSet.hasKey("volumeLoad")) - volumeLoad = make_shared<VolumeLoad>(parameterSet.get<FieldVector<double,3> >("volumeLoad"), + shared_ptr<VolumeLoad> volumeLoad; + if (parameterSet.hasKey("volumeLoad")) + volumeLoad = make_shared<VolumeLoad>(parameterSet.get<FieldVector<double,3> >("volumeLoad"), homotopyParameter); - if (mpiHelper.rank() == 0) { - std::cout << "Material parameters:" << std::endl; - materialParameters.report(); - } + if (mpiHelper.rank() == 0) { + std::cout << "Material parameters:" << std::endl; + materialParameters.report(); + } // Assembler using ADOL-C +#ifdef MIXED_SPACE + CosseratEnergyLocalStiffness<decltype(compositeBasis), + 3,adouble> cosseratEnergyADOLCLocalStiffness(materialParameters, + &neumannBoundary, + neumannFunction, + nullptr); + + MixedLocalGFEADOLCStiffness<decltype(compositeBasis), + RealTuple<double,3>, + Rotation<double,3> > localGFEADOLCStiffness(&cosseratEnergyADOLCLocalStiffness); + + MixedGFEAssembler<decltype(compositeBasis), + RealTuple<double,3>, + Rotation<double,3> > assembler(compositeBasis, &localGFEADOLCStiffness); +#else using LocalEnergyBase = LocalGeodesicFEStiffness<FEBasis,RigidBodyMotion<adouble,3> >; std::shared_ptr<LocalEnergyBase> cosseratEnergyADOLCLocalStiffness; @@ -352,16 +476,33 @@ int main (int argc, char *argv[]) try TargetSpace> localGFEADOLCStiffness(cosseratEnergyADOLCLocalStiffness.get()); GeodesicFEAssembler<FEBasis,TargetSpace> assembler(gridView, &localGFEADOLCStiffness); +#endif // ///////////////////////////////////////////////// // Create a Riemannian trust-region solver // ///////////////////////////////////////////////// +#ifdef MIXED_SPACE + MixedRiemannianTrustRegionSolver<GridType, + decltype(compositeBasis), + DeformationFEBasis, RealTuple<double,3>, + OrientationFEBasis, Rotation<double,3> > solver; +#else RiemannianTrustRegionSolver<FEBasis,TargetSpace> solver; +#endif solver.setup(*grid, &assembler, +#ifdef MIXED_SPACE + deformationFEBasis, + orientationFEBasis, +#endif x, +#ifdef MIXED_SPACE + deformationDirichletDofs, + orientationDirichletDofs, +#else dirichletDofs, +#endif tolerance, maxTrustRegionSteps, initialTrustRegionRadius, @@ -390,9 +531,21 @@ int main (int argc, char *argv[]) try PythonFunction<FieldVector<double,dimworld>, FieldMatrix<double,3,3> > orientationDirichletValues(dirichletValuesPythonObject.get("orientation")); std::vector<FieldVector<double,3> > ddV; - ::Functions::interpolate(fufemFeBasis, ddV, deformationDirichletValues, dirichletDofs); - std::vector<FieldMatrix<double,3,3> > dOV; + +#ifdef MIXED_SPACE + ::Functions::interpolate(fufemDeformationFEBasis, ddV, deformationDirichletValues, deformationDirichletDofs); + ::Functions::interpolate(fufemOrientationFEBasis, dOV, orientationDirichletValues, orientationDirichletDofs); + + for (size_t j=0; j<x[_0].size(); j++) + if (deformationDirichletNodes[j][0]) + x[_0][j] = ddV[j]; + + for (size_t j=0; j<x[_1].size(); j++) + if (orientationDirichletNodes[j][0]) + x[_1][j].set(dOV[j]); +#else + ::Functions::interpolate(fufemFeBasis, ddV, deformationDirichletValues, dirichletDofs); ::Functions::interpolate(fufemFeBasis, dOV, orientationDirichletValues, dirichletDofs); for (size_t j=0; j<x.size(); j++) @@ -401,6 +554,7 @@ int main (int argc, char *argv[]) try x[j].r = ddV[j]; x[j].q.set(dOV[j]); } +#endif // ///////////////////////////////////////////////////// // Solve! @@ -414,7 +568,13 @@ int main (int argc, char *argv[]) try // Output result of each homotopy step std::stringstream iAsAscii; iAsAscii << i+1; +#ifdef MIXED_SPACE + CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,x[_0], + orientationFEBasis,x[_1], + resultPath + "mixed-cosserat_homotopy_" + iAsAscii.str()); +#else CosseratVTKWriter<GridType>::write<FEBasis>(feBasis,x, resultPath + "cosserat_homotopy_" + iAsAscii.str()); +#endif } @@ -422,6 +582,7 @@ int main (int argc, char *argv[]) try // Output result // ////////////////////////////// +#ifndef MIXED_SPACE // Write the corresponding coefficient vector: verbatim in binary, to be completely lossless // This data may be used by other applications measuring the discretization error BlockVector<TargetSpace::CoordinateType> xEmbedded(x.size()); @@ -429,26 +590,31 @@ int main (int argc, char *argv[]) try xEmbedded[i] = x[i].globalCoordinates(); std::ofstream outFile("cosserat-continuum-result-" + std::to_string(numLevels) + ".data", std::ios_base::binary); - GenericVector::writeBinary(outFile, xEmbedded); + MatrixVector::Generic::writeBinary(outFile, xEmbedded); outFile.close(); +#endif // finally: compute the average deformation of the Neumann boundary // That is what we need for the locking tests FieldVector<double,3> averageDef(0); +#ifdef MIXED_SPACE + for (size_t i=0; i<x[_0].size(); i++) + if (neumannNodes[i][0]) + averageDef += x[_0][i].globalCoordinates(); +#else for (size_t i=0; i<x.size(); i++) if (neumannNodes[i][0]) averageDef += x[i].r; +#endif averageDef /= neumannNodes.count(); - if (mpiHelper.rank()==0) + if (mpiHelper.rank()==0 and parameterSet.hasKey("neumannValues")) { std::cout << "Neumann values = " << parameterSet.get<FieldVector<double, 3> >("neumannValues") << " " << ", average deflection: " << averageDef << std::endl; } - // ////////////////////////////// - } catch (Exception e) { - - std::cout << e << std::endl; - - } +} catch (Exception& e) +{ + std::cout << e.what() << std::endl; +} diff --git a/src/gradient-flow.cc b/src/gradient-flow.cc index 3d49ced53f294554a93e8f5782f2ec2a72c491e2..d74c21a2b6237013323989dfff01bf0b8e0fde5f 100644 --- a/src/gradient-flow.cc +++ b/src/gradient-flow.cc @@ -2,13 +2,14 @@ // vi: set et ts=4 sw=2 sts=2: #include <config.h> +#include <array> + // Includes for the ADOL-C automatic differentiation library // Need to come before (almost) all others. #include <adolc/adouble.h> #include <dune/fufem/utilities/adolcnamespaceinjections.hh> -#include <array> - +#include <dune/common/typetraits.hh> #include <dune/common/bitsetvector.hh> #include <dune/common/parametertree.hh> #include <dune/common/parametertreeparser.hh> @@ -22,7 +23,7 @@ #include <dune/grid/io/file/vtk.hh> #include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/fufem/boundarypatch.hh> #include <dune/fufem/functiontools/basisinterpolator.hh> @@ -141,7 +142,7 @@ int main (int argc, char *argv[]) try // Construct the scalar function space basis corresponding to the GFE space ////////////////////////////////////////////////////////////////////////////////// - typedef Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView, order> FEBasis; + typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView, order> FEBasis; //typedef Dune::Functions::Periodic1DPQ1NodalBasis<typename GridType::LeafGridView> FEBasis; FEBasis feBasis(grid->leafGridView()); @@ -201,7 +202,8 @@ int main (int argc, char *argv[]) try auto l2DistanceSquaredEnergy = std::make_shared<L2DistanceSquaredEnergy<FEBasis, ATargetSpace> >(); std::vector<std::shared_ptr<LocalGeodesicFEStiffness<FEBasis,ATargetSpace> > > addends(2); - addends[0] = std::make_shared<HarmonicEnergyLocalStiffness<FEBasis, ATargetSpace> >(); + using GeodesicInterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>; + addends[0] = std::make_shared<HarmonicEnergyLocalStiffness<FEBasis, GeodesicInterpolationRule, ATargetSpace> >(); addends[1] = l2DistanceSquaredEnergy; std::vector<double> weights = {1.0, 1.0/(2*timeStepSize)}; @@ -244,13 +246,13 @@ int main (int argc, char *argv[]) try TypeTree::hybridTreePath(), xEmbedded); - SubsamplingVTKWriter<GridType::LeafGridView> vtkWriter(grid->leafGridView(),0); + SubsamplingVTKWriter<GridType::LeafGridView> vtkWriter(grid->leafGridView(),refinementLevels(0)); vtkWriter.addVertexData(xFunction, VTK::FieldInfo("orientation", VTK::FieldInfo::Type::scalar, xEmbedded[0].size())); vtkWriter.write("gradientflow_result_0"); // Write the corresponding coefficient vector: verbatim in binary, to be completely lossless std::ofstream outFile("gradientflow_result_0.data", std::ios_base::binary); - GenericVector::writeBinary(outFile, xEmbedded); + MatrixVector::Generic::writeBinary(outFile, xEmbedded); outFile.close(); /////////////////////////////////////////////////////// @@ -284,21 +286,21 @@ int main (int argc, char *argv[]) try TypeTree::hybridTreePath(), xEmbedded); - SubsamplingVTKWriter<GridType::LeafGridView> vtkWriter(grid->leafGridView(),0); + SubsamplingVTKWriter<GridType::LeafGridView> vtkWriter(grid->leafGridView(),refinementLevels(0)); vtkWriter.addVertexData(xFunction, VTK::FieldInfo("orientation", VTK::FieldInfo::Type::scalar, xEmbedded[0].size())); vtkWriter.write("gradientflow_result_" + std::to_string(i+1)); // Write the corresponding coefficient vector: verbatim in binary, to be completely lossless std::ofstream outFile("gradientflow_result_" + std::to_string(i+1) + ".data", std::ios_base::binary); - GenericVector::writeBinary(outFile, xEmbedded); + MatrixVector::Generic::writeBinary(outFile, xEmbedded); outFile.close(); } return 0; } -catch (Exception e) +catch (Exception& e) { - std::cout << e << std::endl; + std::cout << e.what() << std::endl; return 1; } diff --git a/src/harmonicmaps.cc b/src/harmonicmaps.cc index 4717e6c181663cc0ffe9a3a2bbe25c3b305e0de5..00479169a3d0f26ac02e1d265e6d6c0222053401 100644 --- a/src/harmonicmaps.cc +++ b/src/harmonicmaps.cc @@ -1,6 +1,7 @@ #include <config.h> #include <fenv.h> +#include <array> // Includes for the ADOL-C automatic differentiation library // Need to come before (almost) all others. @@ -8,30 +9,27 @@ #include <dune/fufem/utilities/adolcnamespaceinjections.hh> #include <dune/common/typetraits.hh> -namespace Dune { - template <> - struct IsNumber<adouble> - { - constexpr static bool value = true; - }; -} - -#include <array> #include <dune/common/bitsetvector.hh> #include <dune/common/parametertree.hh> #include <dune/common/parametertreeparser.hh> #include <dune/grid/uggrid.hh> -#include <dune/grid/onedgrid.hh> #include <dune/grid/utility/structuredgridfactory.hh> #include <dune/grid/io/file/gmshreader.hh> #include <dune/grid/io/file/vtk.hh> +#if HAVE_DUNE_FOAMGRID +#include <dune/foamgrid/foamgrid.hh> +#else +#include <dune/grid/onedgrid.hh> +#endif + #include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/functions/functionspacebases/bsplinebasis.hh> +#include <dune/functions/functionspacebases/powerbasis.hh> #include <dune/functions/functionspacebases/interpolate.hh> #include <dune/fufem/boundarypatch.hh> @@ -45,6 +43,7 @@ namespace Dune { #include <dune/gfe/rotation.hh> #include <dune/gfe/unitvector.hh> #include <dune/gfe/realtuple.hh> +#include <dune/gfe/rigidbodymotion.hh> #include <dune/gfe/localgeodesicfefunction.hh> #include <dune/gfe/localprojectedfefunction.hh> #include <dune/gfe/localgeodesicfeadolcstiffness.hh> @@ -56,10 +55,12 @@ namespace Dune { // grid dimension const int dim = 2; +const int dimworld = 2; // Image space of the geodesic fe functions // typedef Rotation<double,2> TargetSpace; // typedef Rotation<double,3> TargetSpace; +// typedef RigidBodyMotion<double,3> TargetSpace; // typedef UnitVector<double,2> TargetSpace; typedef UnitVector<double,3> TargetSpace; // typedef UnitVector<double,4> TargetSpace; @@ -74,6 +75,51 @@ const int order = 1; using namespace Dune; +template <typename Writer, typename Basis, typename SolutionType> +void fillVTKWriter(Writer& vtkWriter, const Basis& feBasis, const SolutionType& x, std::string filename) +{ + typedef BlockVector<TargetSpace::CoordinateType> EmbeddedVectorType; + EmbeddedVectorType xEmbedded(x.size()); + for (size_t i=0; i<x.size(); i++) + xEmbedded[i] = x[i].globalCoordinates(); + + if constexpr (std::is_same<TargetSpace, Rotation<double,3> >::value) + { + std::array<BlockVector<FieldVector<double,3> >,3> director; + for (int i=0; i<3; i++) + director[i].resize(x.size()); + + for (size_t i=0; i<x.size(); i++) + { + FieldMatrix<double,3,3> m; + x[i].matrix(m); + director[0][i] = {m[0][0], m[1][0], m[2][0]}; + director[1][i] = {m[0][1], m[1][1], m[2][1]}; + director[2][i] = {m[0][2], m[1][2], m[2][2]}; + } + + auto dFunction0 = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3> >(feBasis,director[0]); + auto dFunction1 = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3> >(feBasis,director[1]); + auto dFunction2 = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3> >(feBasis,director[2]); + + vtkWriter.addVertexData(dFunction0, VTK::FieldInfo("director0", VTK::FieldInfo::Type::vector, 3)); + vtkWriter.addVertexData(dFunction1, VTK::FieldInfo("director1", VTK::FieldInfo::Type::vector, 3)); + vtkWriter.addVertexData(dFunction2, VTK::FieldInfo("director2", VTK::FieldInfo::Type::vector, 3)); + + // Needs to be in this scope; otherwise the stack-allocated dFunction?-objects will get + // destructed before 'write' is called. + vtkWriter.write(filename); + } + else + { + auto xFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<TargetSpace::CoordinateType>(feBasis,TypeTree::hybridTreePath(),xEmbedded); + + vtkWriter.addVertexData(xFunction, VTK::FieldInfo("orientation", VTK::FieldInfo::Type::vector, xEmbedded[0].size())); + + vtkWriter.write(filename); + } +} + int main (int argc, char *argv[]) { @@ -124,17 +170,22 @@ int main (int argc, char *argv[]) // /////////////////////////////////////// // Create the grid // /////////////////////////////////////// +#if HAVE_DUNE_FOAMGRID + typedef std::conditional<dim==1 or dim!=dimworld,FoamGrid<dim,dimworld>,UGGrid<dim> >::type GridType; +#else + static_assert(dim==dimworld, "You need to have dune-foamgrid installed for dim != dimworld!"); typedef std::conditional<dim==1,OneDGrid,UGGrid<dim> >::type GridType; +#endif shared_ptr<GridType> grid; - FieldVector<double,dim> lower(0), upper(1); + FieldVector<double,dimworld> lower(0), upper(1); std::array<unsigned int,dim> elements; std::string structuredGridType = parameterSet["structuredGrid"]; if (structuredGridType != "false" ) { - lower = parameterSet.get<FieldVector<double,dim> >("lower"); - upper = parameterSet.get<FieldVector<double,dim> >("upper"); + lower = parameterSet.get<FieldVector<double,dimworld> >("lower"); + upper = parameterSet.get<FieldVector<double,dimworld> >("upper"); elements = parameterSet.get<std::array<unsigned int,dim> >("elements"); if (structuredGridType == "simplex") @@ -161,7 +212,7 @@ int main (int argc, char *argv[]) using GridView = GridType::LeafGridView; GridView gridView = grid->leafGridView(); #ifdef LAGRANGE - typedef Dune::Functions::PQkNodalBasis<GridView, order> FEBasis; + typedef Dune::Functions::LagrangeBasis<GridView, order> FEBasis; FEBasis feBasis(gridView); #else typedef Dune::Functions::BSplineBasis<GridView> FEBasis; @@ -180,7 +231,7 @@ int main (int argc, char *argv[]) // Make Python function that computes which vertices are on the Dirichlet boundary, // based on the vertex positions. std::string lambda = std::string("lambda x: (") + parameterSet.get<std::string>("dirichletVerticesPredicate") + std::string(")"); - PythonFunction<FieldVector<double,dim>, bool> pythonDirichletVertices(Python::evaluate(lambda)); + PythonFunction<FieldVector<double,dimworld>, bool> pythonDirichletVertices(Python::evaluate(lambda)); for (auto&& vertex : vertices(gridView)) { @@ -205,13 +256,22 @@ int main (int argc, char *argv[]) // Read initial iterate into a PythonFunction Python::Module module = Python::import(parameterSet.get<std::string>("initialIterate")); - auto pythonInitialIterate = Python::makeFunction<TargetSpace::CoordinateType(const FieldVector<double,dim>&)>(module.get("f")); + auto pythonInitialIterate = Python::makeFunction<TargetSpace::CoordinateType(const FieldVector<double,dimworld>&)>(module.get("f")); std::vector<TargetSpace::CoordinateType> v; + using namespace Functions::BasisFactory; + + auto powerBasis = makeBasis( + gridView, + power<TargetSpace::CoordinateType::dimension>( + lagrange<order>(), + blockedInterleaved() + )); + #ifdef LAGRANGE - Dune::Functions::interpolate(feBasis, v, pythonInitialIterate); + Dune::Functions::interpolate(powerBasis, v, pythonInitialIterate); #else - Dune::Functions::interpolate(feBasis, v, pythonInitialIterate, lower, upper, elements, order); + Dune::Functions::interpolate(powerBasis, v, pythonInitialIterate, lower, upper, elements, order); #endif for (size_t i=0; i<x.size(); i++) @@ -225,9 +285,8 @@ int main (int argc, char *argv[]) // //////////////////////////////////////////////////////////// typedef TargetSpace::rebind<adouble>::other ATargetSpace; - typedef LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace> LocalInterpolationRule; - //typedef GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace> LocalInterpolationRule; - std::cout << "Using local interpolation: " << className<LocalInterpolationRule>() << std::endl; + using GeodesicInterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>; + using ProjectedInterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>; // Assembler using ADOL-C std::shared_ptr<LocalGeodesicFEStiffness<FEBasis,ATargetSpace> > localEnergy; @@ -235,13 +294,26 @@ int main (int argc, char *argv[]) std::string energy = parameterSet.get<std::string>("energy"); if (energy == "harmonic") { - - localEnergy.reset(new HarmonicEnergyLocalStiffness<FEBasis, LocalInterpolationRule, ATargetSpace>); + if (parameterSet["interpolationMethod"] == "geodesic") + localEnergy.reset(new HarmonicEnergyLocalStiffness<FEBasis, GeodesicInterpolationRule, ATargetSpace>); + else if (parameterSet["interpolationMethod"] == "projected") + localEnergy.reset(new HarmonicEnergyLocalStiffness<FEBasis, ProjectedInterpolationRule, ATargetSpace>); + else + DUNE_THROW(Exception, "Unknown interpolation method " << parameterSet["interpolationMethod"] << " requested!"); } else if (energy == "chiral_skyrmion") { - - localEnergy.reset(new GFE::ChiralSkyrmionEnergy<FEBasis, LocalInterpolationRule, adouble>(parameterSet.sub("energyParameters"))); +// // Doesn't work: we are not inside of a template +// if constexpr (std::is_same<TargetSpace, UnitVector<double,3> >::value) +// { + if (parameterSet["interpolationMethod"] == "geodesic") + localEnergy.reset(new GFE::ChiralSkyrmionEnergy<FEBasis, GeodesicInterpolationRule, adouble>(parameterSet.sub("energyParameters"))); + else if (parameterSet["interpolationMethod"] == "projected") + localEnergy.reset(new GFE::ChiralSkyrmionEnergy<FEBasis, ProjectedInterpolationRule, adouble>(parameterSet.sub("energyParameters"))); + else + DUNE_THROW(Exception, "Unknown interpolation method " << parameterSet["interpolationMethod"] << " requested!"); +// } else +// DUNE_THROW(Exception, "Build program with TargetSpace = UnitVector<3> for the ChiralSkyrmion energy!"); } else DUNE_THROW(Exception, "Unknown energy type '" << energy << "'"); @@ -273,9 +345,6 @@ int main (int argc, char *argv[]) // Solve! // ///////////////////////////////////////////////////// - std::cout << "Energy: " << assembler.computeEnergy(x) << std::endl; - //exit(0); - solver.setInitialIterate(x); solver.solve(); @@ -285,20 +354,16 @@ int main (int argc, char *argv[]) // Output result // ////////////////////////////// + SubsamplingVTKWriter<GridView> vtkWriter(gridView,Dune::refinementLevels(order-1)); + std::string baseName = "harmonicmaps-result-" + std::to_string(order) + "-" + std::to_string(numLevels); + fillVTKWriter(vtkWriter, feBasis, x, resultPath + baseName); + + // Write the corresponding coefficient vector: verbatim in binary, to be completely lossless typedef BlockVector<TargetSpace::CoordinateType> EmbeddedVectorType; EmbeddedVectorType xEmbedded(x.size()); for (size_t i=0; i<x.size(); i++) - xEmbedded[i] = x[i].globalCoordinates(); - - auto xFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<TargetSpace::CoordinateType>(feBasis,TypeTree::hybridTreePath(),xEmbedded); + xEmbedded[i] = x[i].globalCoordinates(); - std::string baseName = "harmonicmaps-result-" + std::to_string(order) + "-" + std::to_string(numLevels); - - SubsamplingVTKWriter<GridView> vtkWriter(gridView,order-1); - vtkWriter.addVertexData(xFunction, VTK::FieldInfo("orientation", VTK::FieldInfo::Type::vector, xEmbedded[0].size())); - vtkWriter.write(resultPath + baseName); - - // Write the corresponding coefficient vector: verbatim in binary, to be completely lossless std::ofstream outFile(baseName + ".data", std::ios_base::binary); MatrixVector::Generic::writeBinary(outFile, xEmbedded); outFile.close(); diff --git a/src/mixed-cosserat-continuum.cc b/src/mixed-cosserat-continuum.cc deleted file mode 100644 index 5702b0326df654ce4859cf3271e5aac3d75aab39..0000000000000000000000000000000000000000 --- a/src/mixed-cosserat-continuum.cc +++ /dev/null @@ -1,409 +0,0 @@ -#include <config.h> - -#include <fenv.h> - -// Includes for the ADOL-C automatic differentiation library -// Need to come before (almost) all others. -#include <adolc/adouble.h> -#include <adolc/drivers/drivers.h> // use of "Easy to Use" drivers -#include <adolc/taping.h> - -#include <dune/fufem/utilities/adolcnamespaceinjections.hh> - -#include <array> - -#include <dune/common/bitsetvector.hh> -#include <dune/common/parametertree.hh> -#include <dune/common/parametertreeparser.hh> - -#include <dune/grid/uggrid.hh> -#include <dune/grid/onedgrid.hh> -#include <dune/grid/utility/structuredgridfactory.hh> - -#include <dune/grid/io/file/gmshreader.hh> - -#include <dune/functions/common/tuplevector.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> -#include <dune/functions/functionspacebases/compositebasis.hh> - -#include <dune/fufem/boundarypatch.hh> -#include <dune/fufem/functiontools/boundarydofs.hh> -#include <dune/fufem/functiontools/basisinterpolator.hh> -#include <dune/fufem/functionspacebases/dunefunctionsbasis.hh> -#include <dune/fufem/dunepython.hh> - -#include <dune/solvers/solvers/iterativesolver.hh> -#include <dune/solvers/norms/energynorm.hh> - -#include <dune/gfe/rigidbodymotion.hh> -#include <dune/gfe/mixedlocalgfeadolcstiffness.hh> -#include <dune/gfe/cosseratenergystiffness.hh> -#include <dune/gfe/cosseratvtkwriter.hh> -#include <dune/gfe/mixedgfeassembler.hh> -#include <dune/gfe/mixedriemanniantrsolver.hh> - -// grid dimension -const int dim = 2; - -using namespace Dune; - -/** \brief A constant vector-valued function, for simple Neumann boundary values */ -struct NeumannFunction - : public Dune::VirtualFunction<FieldVector<double,dim>, FieldVector<double,3> > -{ - NeumannFunction(const FieldVector<double,3> values, - double homotopyParameter) - : values_(values), - homotopyParameter_(homotopyParameter) - {} - - void evaluate(const FieldVector<double, dim>& x, FieldVector<double,3>& out) const { - out = 0; - out.axpy(homotopyParameter_, values_); - } - - FieldVector<double,3> values_; - double homotopyParameter_; -}; - - -int main (int argc, char *argv[]) try -{ - // initialize MPI, finalize is done automatically on exit - Dune::MPIHelper& mpiHelper = MPIHelper::instance(argc, argv); - - // Start Python interpreter - Python::start(); - Python::Reference main = Python::import("__main__"); - Python::run("import math"); - - //feenableexcept(FE_INVALID); - Python::runStream() - << std::endl << "import sys" - << std::endl << "sys.path.append('/home/sander/dune/dune-gfe/problems/')" - << std::endl; - - using namespace Dune::TypeTree::Indices; - typedef Dune::Functions::TupleVector<std::vector<RealTuple<double,3> >, - std::vector<Rotation<double,3> > > SolutionType; - - // parse data file - ParameterTree parameterSet; - if (argc < 2) - DUNE_THROW(Exception, "Usage: ./mixed-cosserat-continuum <parameter file>"); - - ParameterTreeParser::readINITree(argv[1], parameterSet); - - ParameterTreeParser::readOptions(argc, argv, parameterSet); - - // read solver settings - const int numLevels = parameterSet.get<int>("numLevels"); - int numHomotopySteps = parameterSet.get<int>("numHomotopySteps"); - const double tolerance = parameterSet.get<double>("tolerance"); - const int maxTrustRegionSteps = parameterSet.get<int>("maxTrustRegionSteps"); - const double initialTrustRegionRadius = parameterSet.get<double>("initialTrustRegionRadius"); - const int multigridIterations = parameterSet.get<int>("numIt"); - const int nu1 = parameterSet.get<int>("nu1"); - const int nu2 = parameterSet.get<int>("nu2"); - const int mu = parameterSet.get<int>("mu"); - const int baseIterations = parameterSet.get<int>("baseIt"); - const double mgTolerance = parameterSet.get<double>("mgTolerance"); - const double baseTolerance = parameterSet.get<double>("baseTolerance"); - const bool instrumented = parameterSet.get<bool>("instrumented"); - std::string resultPath = parameterSet.get("resultPath", ""); - - // /////////////////////////////////////// - // Create the grid - // /////////////////////////////////////// - typedef std::conditional<dim==1,OneDGrid,UGGrid<dim> >::type GridType; - - shared_ptr<GridType> grid; - - FieldVector<double,dim> lower(0), upper(1); - - if (parameterSet.get<bool>("structuredGrid")) { - - lower = parameterSet.get<FieldVector<double,dim> >("lower"); - upper = parameterSet.get<FieldVector<double,dim> >("upper"); - - auto elements = parameterSet.get<std::array<unsigned int,dim> >("elements"); - grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements); - - } else { - std::string path = parameterSet.get<std::string>("path"); - std::string gridFile = parameterSet.get<std::string>("gridFile"); - grid = shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile)); - } - - grid->globalRefine(numLevels-1); - - grid->loadBalance(); - - if (mpiHelper.rank()==0) - std::cout << "There are " << grid->leafGridView().comm().size() << " processes" << std::endl; - - typedef GridType::LeafGridView GridView; - GridView gridView = grid->leafGridView(); - - using namespace Dune::Functions::BasisBuilder; - - auto compositeBasis = makeBasis( - gridView, - composite( - pq<2>(), - pq<1>() - ) - ); - - typedef Dune::Functions::PQkNodalBasis<GridView,2> DeformationFEBasis; - typedef Dune::Functions::PQkNodalBasis<GridView,1> OrientationFEBasis; - - DeformationFEBasis deformationFEBasis(gridView); - OrientationFEBasis orientationFEBasis(gridView); - - // Construct fufem-style function space bases to ease the transition to dune-functions - typedef DuneFunctionsBasis<DeformationFEBasis> FufemDeformationFEBasis; - FufemDeformationFEBasis fufemDeformationFEBasis(deformationFEBasis); - - typedef DuneFunctionsBasis<OrientationFEBasis> FufemOrientationFEBasis; - FufemOrientationFEBasis fufemOrientationFEBasis(orientationFEBasis); - - - - std::cout << "Deformation: " << deformationFEBasis.size() << ", orientation: " << orientationFEBasis.size() << std::endl; - - // ///////////////////////////////////////// - // Read Dirichlet values - // ///////////////////////////////////////// - - BitSetVector<1> dirichletVertices(gridView.size(dim), false); - BitSetVector<1> neumannVertices(gridView.size(dim), false); - - GridType::Codim<dim>::LeafIterator vIt = gridView.begin<dim>(); - GridType::Codim<dim>::LeafIterator vEndIt = gridView.end<dim>(); - - const GridView::IndexSet& indexSet = gridView.indexSet(); - - // Make Python function that computes which vertices are on the Dirichlet boundary, - // based on the vertex positions. - std::string lambda = std::string("lambda x: (") + parameterSet.get<std::string>("dirichletVerticesPredicate") + std::string(")"); - PythonFunction<FieldVector<double,dim>, bool> pythonDirichletVertices(Python::evaluate(lambda)); - - // Same for the Neumann boundary - lambda = std::string("lambda x: (") + parameterSet.get<std::string>("neumannVerticesPredicate", "0") + std::string(")"); - PythonFunction<FieldVector<double,dim>, bool> pythonNeumannVertices(Python::evaluate(lambda)); - - for (; vIt!=vEndIt; ++vIt) { - - bool isDirichlet; - pythonDirichletVertices.evaluate(vIt->geometry().corner(0), isDirichlet); - dirichletVertices[indexSet.index(*vIt)] = isDirichlet; - - bool isNeumann; - pythonNeumannVertices.evaluate(vIt->geometry().corner(0), isNeumann); - neumannVertices[indexSet.index(*vIt)] = isNeumann; - - } - - BoundaryPatch<GridView> dirichletBoundary(gridView, dirichletVertices); - BoundaryPatch<GridView> neumannBoundary(gridView, neumannVertices); - - BitSetVector<1> neumannNodes(deformationFEBasis.size(), false); - constructBoundaryDofs(neumannBoundary,fufemDeformationFEBasis,neumannNodes); - - - if (mpiHelper.rank()==0) - std::cout << "Neumann boundary has " << neumannBoundary.numFaces() << " faces\n"; - - - BitSetVector<1> deformationDirichletNodes(deformationFEBasis.size(), false); - constructBoundaryDofs(dirichletBoundary,fufemDeformationFEBasis,deformationDirichletNodes); - - BitSetVector<3> deformationDirichletDofs(deformationFEBasis.size(), false); - for (size_t i=0; i<deformationFEBasis.size(); i++) - if (deformationDirichletNodes[i][0]) - for (int j=0; j<3; j++) - deformationDirichletDofs[i][j] = true; - - BitSetVector<1> orientationDirichletNodes(orientationFEBasis.size(), false); - constructBoundaryDofs(dirichletBoundary,fufemOrientationFEBasis,orientationDirichletNodes); - - BitSetVector<3> orientationDirichletDofs(orientationFEBasis.size(), false); - for (size_t i=0; i<orientationFEBasis.size(); i++) - if (orientationDirichletNodes[i][0]) - for (int j=0; j<3; j++) - orientationDirichletDofs[i][j] = true; - - // ////////////////////////// - // Initial iterate - // ////////////////////////// - - SolutionType x; - - x[_0].resize(deformationFEBasis.size()); - - lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")"); - PythonFunction<FieldVector<double,dim>, FieldVector<double,3> > pythonInitialDeformation(Python::evaluate(lambda)); - - std::vector<FieldVector<double,3> > v; - ::Functions::interpolate(fufemDeformationFEBasis, v, pythonInitialDeformation); - - for (size_t i=0; i<x[_0].size(); i++) - x[_0][i] = v[i]; - - x[_1].resize(orientationFEBasis.size()); -#if 0 - lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")"); - PythonFunction<FieldVector<double,dim>, FieldVector<double,3> > pythonInitialDeformation(Python::evaluate(lambda)); - - std::vector<FieldVector<double,3> > v; - Functions::interpolate(feBasis, v, pythonInitialDeformation); - - for (size_t i=0; i<x.size(); i++) - xDisp[i] = v[i]; -#endif - //////////////////////////////////////////////////////// - // Main homotopy loop - //////////////////////////////////////////////////////// - - // Output initial iterate (of homotopy loop) - CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,x[_0], - orientationFEBasis,x[_1], - resultPath + "mixed-cosserat_homotopy_0"); - - for (int i=0; i<numHomotopySteps; i++) { - - double homotopyParameter = (i+1)*(1.0/numHomotopySteps); - if (mpiHelper.rank()==0) - std::cout << "Homotopy step: " << i << ", parameter: " << homotopyParameter << std::endl; - - - // //////////////////////////////////////////////////////////// - // Create an assembler for the energy functional - // //////////////////////////////////////////////////////////// - - const ParameterTree& materialParameters = parameterSet.sub("materialParameters"); - - shared_ptr<NeumannFunction> neumannFunction; - if (parameterSet.hasKey("neumannValues")) - neumannFunction = make_shared<NeumannFunction>(parameterSet.get<FieldVector<double,3> >("neumannValues"), - homotopyParameter); - - - if (mpiHelper.rank() == 0) { - std::cout << "Material parameters:" << std::endl; - materialParameters.report(); - } - - // Assembler using ADOL-C - CosseratEnergyLocalStiffness<decltype(compositeBasis), - 3,adouble> cosseratEnergyADOLCLocalStiffness(materialParameters, - &neumannBoundary, - neumannFunction, - nullptr); - - MixedLocalGFEADOLCStiffness<decltype(compositeBasis), - RealTuple<double,3>, - Rotation<double,3> > localGFEADOLCStiffness(&cosseratEnergyADOLCLocalStiffness); - - MixedGFEAssembler<decltype(compositeBasis), - RealTuple<double,3>, - Rotation<double,3> > assembler(compositeBasis, &localGFEADOLCStiffness); - - // ///////////////////////////////////////////////// - // Create a Riemannian trust-region solver - // ///////////////////////////////////////////////// - - MixedRiemannianTrustRegionSolver<GridType, - decltype(compositeBasis), - DeformationFEBasis, RealTuple<double,3>, - OrientationFEBasis, Rotation<double,3> > solver; - solver.setup(*grid, - &assembler, - deformationFEBasis, - orientationFEBasis, - x, - deformationDirichletDofs, - orientationDirichletDofs, - tolerance, - maxTrustRegionSteps, - initialTrustRegionRadius, - multigridIterations, - mgTolerance, - mu, nu1, nu2, - baseIterations, - baseTolerance, - instrumented); - - solver.setScaling(parameterSet.get<FieldVector<double,6> >("trustRegionScaling")); - - //////////////////////////////////////////////////////// - // Set Dirichlet values - //////////////////////////////////////////////////////// - - Python::Reference dirichletValuesClass = Python::import(parameterSet.get<std::string>("problem") + "-dirichlet-values"); - - Python::Callable C = dirichletValuesClass.get("DirichletValues"); - - // Call a constructor. - Python::Reference dirichletValuesPythonObject = C(homotopyParameter); - - // Extract object member functions as Dune functions - PythonFunction<FieldVector<double,dim>, FieldVector<double,3> > deformationDirichletValues(dirichletValuesPythonObject.get("deformation")); - PythonFunction<FieldVector<double,dim>, FieldMatrix<double,3,3> > orientationDirichletValues(dirichletValuesPythonObject.get("orientation")); - - std::vector<FieldVector<double,3> > ddV; - ::Functions::interpolate(fufemDeformationFEBasis, ddV, deformationDirichletValues, deformationDirichletDofs); - - std::vector<FieldMatrix<double,3,3> > dOV; - ::Functions::interpolate(fufemOrientationFEBasis, dOV, orientationDirichletValues, orientationDirichletDofs); - - for (size_t j=0; j<x[_0].size(); j++) - if (deformationDirichletNodes[j][0]) - x[_0][j] = ddV[j]; - - for (size_t j=0; j<x[_1].size(); j++) - if (orientationDirichletNodes[j][0]) - x[_1][j].set(dOV[j]); - - // ///////////////////////////////////////////////////// - // Solve! - // ///////////////////////////////////////////////////// - - solver.setInitialIterate(x); - solver.solve(); - - x = solver.getSol(); - - // Output result of each homotopy step - std::stringstream iAsAscii; - iAsAscii << i+1; - CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,x[_0], - orientationFEBasis,x[_1], - resultPath + "mixed-cosserat_homotopy_" + iAsAscii.str()); - - } - - // ////////////////////////////// - // Output result - // ////////////////////////////// - - // finally: compute the average deformation of the Neumann boundary - // That is what we need for the locking tests - FieldVector<double,3> averageDef(0); - for (size_t i=0; i<x[_0].size(); i++) - if (neumannNodes[i][0]) - averageDef += x[_0][i].globalCoordinates(); - averageDef /= neumannNodes.count(); - - if (mpiHelper.rank()==0) - { - std::cout << "Neumann values = " << parameterSet.get<FieldVector<double, 3> >("neumannValues") << " " - << ", average deflection: " << averageDef << std::endl; - } - - } catch (Exception e) { - - std::cout << e << std::endl; - - } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4035fd75736fbd73201cdafbfd0b88c74c463443..b1a268f13fe44ede63c4e355b5e1640b3e61dfce 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -18,12 +18,7 @@ set(TESTS targetspacetest ) -add_directory_test_target(_test_target) -add_dependencies(${_test_target} ${TESTS}) - foreach(_test ${TESTS}) - add_executable(${_test} ${_test}.cc) - target_link_libraries(${_test} ${DUNE_LIBS}) - add_dune_ug_flags(${_test}) - add_test(${_test} ${_test}) + dune_add_test(SOURCES ${_test}.cc) + target_compile_options(${_test} PRIVATE -g) endforeach() diff --git a/test/adolctest.cc b/test/adolctest.cc index 603db78ffafb3bd102314070f213876e44419ac7..523d7406fba0780826d01b43adff77092d9216a0 100644 --- a/test/adolctest.cc +++ b/test/adolctest.cc @@ -25,6 +25,17 @@ typedef double FDType; #include <adolc/taping.h> #include <dune/fufem/utilities/adolcnamespaceinjections.hh> + +#include <dune/common/typetraits.hh> +// This specialization is needed (in particular) to make copying of FieldMatrices work. +namespace Dune { + template <> + struct IsNumber<adouble> + { + constexpr static bool value = true; + }; +} + #include <dune/common/fmatrix.hh> #include <dune/geometry/quadraturerules.hh> @@ -33,7 +44,7 @@ typedef double FDType; #include <dune/istl/io.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/functions/functionspacebases/interpolate.hh> @@ -429,7 +440,7 @@ int main (int argc, char *argv[]) try typedef GridType::LeafGridView GridView; GridView gridView = grid.leafGridView(); - typedef Functions::PQkNodalBasis<GridView,2> FEBasis; + typedef Functions::LagrangeBasis<GridView,1> FEBasis; FEBasis feBasis(gridView); // ///////////////////////////////////////// @@ -577,7 +588,7 @@ int main (int argc, char *argv[]) try } // ////////////////////////////// - } catch (Exception e) { + } catch (Exception& e) { std::cout << e << std::endl; diff --git a/test/averagedistanceassemblertest.cc b/test/averagedistanceassemblertest.cc index 0f49c4a40b4e511cd225eeec82fe5490f692a5ae..5aa37cc1d06755541bbf6d4f8f3ce2db1901c458 100644 --- a/test/averagedistanceassemblertest.cc +++ b/test/averagedistanceassemblertest.cc @@ -66,7 +66,7 @@ void testWeightSet(const std::vector<TargetSpace>& corners, int quadOrder = 3; const Dune::QuadratureRule<double, dim>& quad - = Dune::QuadratureRules<double, dim>::rule(GeometryType(GeometryType::simplex,dim), quadOrder); + = Dune::QuadratureRules<double, dim>::rule(GeometryTypes::simplex(dim), quadOrder); for (size_t pt=0; pt<quad.size(); pt++) { diff --git a/test/cosseratenergytest.cc b/test/cosseratenergytest.cc index 6881cb5d5f0649c95a7961fe3f6f158f2b03dd4c..d74cc9a4f372fc22a5f9f2494a1ba08ed443b4f3 100644 --- a/test/cosseratenergytest.cc +++ b/test/cosseratenergytest.cc @@ -6,7 +6,7 @@ #include <dune/geometry/type.hh> #include <dune/geometry/quadraturerules.hh> -#include <dune/functions/functionspacebases/pqknodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/fufem/functions/constantfunction.hh> @@ -119,7 +119,7 @@ void testDerivativeOfRotationMatrix(const std::vector<TargetSpace>& corners) Dune::FieldMatrix<double, TargetSpace::EmbeddedTangentVector::dimension, domainDim> derivative = f.evaluateDerivative(quadPos); Tensor3<double,3,3,domainDim> DR; - typedef Dune::Functions::PQkNodalBasis<typename UGGrid<domainDim>::LeafGridView,1> FEBasis; + typedef Dune::Functions::LagrangeBasis<typename UGGrid<domainDim>::LeafGridView,1> FEBasis; CosseratEnergyLocalStiffness<FEBasis,3>::computeDR(f.evaluate(quadPos),derivative, DR); // evaluate fd approximation of derivative @@ -157,7 +157,7 @@ void testEnergy(const GridType* grid, const std::vector<TargetSpace>& coefficien materialParameters["q"] = "2.5"; materialParameters["kappa"] = "0.1"; - typedef Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> FEBasis; + typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> FEBasis; FEBasis feBasis(grid->leafGridView()); CosseratEnergyLocalStiffness<FEBasis,3> assembler(materialParameters, @@ -349,7 +349,7 @@ int main(int argc, char** argv) // Create a local assembler object //////////////////////////////////////////////////////////////////////////// - typedef Dune::Functions::PQkNodalBasis<typename GridType::LeafGridView,1> Basis; + typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,1> Basis; Basis basis(grid->leafGridView()); std::cout << " --- Testing derivative of rotation matrix, domain dimension: " << domainDim << " ---" << std::endl; diff --git a/test/frameinvariancetest.cc b/test/frameinvariancetest.cc index 95180a69423e3c017acd89001dd6c8c8500f0c7f..24b4151c157ea72326730a4bc91ccc78a8d3adf8 100644 --- a/test/frameinvariancetest.cc +++ b/test/frameinvariancetest.cc @@ -23,8 +23,6 @@ using std::string; int main (int argc, char *argv[]) try { // Some types that I need - typedef BCRSMatrix<FieldMatrix<double, blocksize, blocksize> > MatrixType; - typedef BlockVector<FieldVector<double, blocksize> > CorrectionType; typedef std::vector<RigidBodyMotion<double,3> > SolutionType; // Problem settings @@ -35,8 +33,10 @@ int main (int argc, char *argv[]) try // /////////////////////////////////////// typedef OneDGrid GridType; GridType grid(numRodBaseElements, 0, 1); + using GridView = GridType::LeafGridView; + GridView gridView = grid.leafGridView(); - SolutionType x(grid.size(1)); + SolutionType x(gridView.size(1)); // ////////////////////////// // Initial solution @@ -57,10 +57,7 @@ int main (int argc, char *argv[]) try // Create a second, rotated copy of the configuration // ///////////////////////////////////////////////////////////////////// - FieldVector<double,3> displacement; - displacement[0] = 0; - displacement[1] = 0; - displacement[2] = 0; + FieldVector<double,3> displacement {0, 0, 0}; FieldVector<double,3> axis(0); axis[0]=1; Rotation<double,3> rotation(axis,M_PI/2); @@ -88,20 +85,20 @@ int main (int argc, char *argv[]) try writeRod(x,"rod"); writeRod(rotatedX, "rotated"); - RodLocalStiffness<GridType::LeafGridView,double> assembler(grid.leafGridView(), + RodLocalStiffness<GridView,double> assembler(gridView, 1,1,1,1e6,0.3); for (int i=1; i<2; i++) { double p = double(i)/2; - assembler.getStrain(x,*grid.lbegin<0>(0), p); - assembler.getStrain(rotatedX,*grid.lbegin<0>(0), p); + assembler.getStrain(x,*gridView.begin<0>(), p); + assembler.getStrain(rotatedX,*gridView.begin<0>(), p); } - } catch (Exception e) { + } catch (Exception& e) { - std::cout << e << std::endl; + std::cout << e.what() << std::endl; } diff --git a/test/globalgfetestfunctionbasistest.cc b/test/globalgfetestfunctionbasistest.cc index beb1d7197b7c233dd603ebd2ff31243f93f39015..16e8cc5399c75cbbdcc4601652760d5a8a79cc0b 100644 --- a/test/globalgfetestfunctionbasistest.cc +++ b/test/globalgfetestfunctionbasistest.cc @@ -41,19 +41,17 @@ void test() typedef GlobalGFETestFunctionBasis<P1Basis,TargetSpace> GlobalBasis; GlobalBasis basis(p1Basis,testPoints); - typedef typename OneDGrid::Codim<0>::LeafIterator ElementIterator; - ElementIterator eIt = grid.leafbegin<0>(); - ElementIterator eEndIt = grid.leafend<0>(); - - for (; eIt != eEndIt; ++eIt) { - - const typename GlobalBasis::LocalFiniteElement& lfe = basis.getLocalFiniteElement(*eIt); + for (const auto element : elements(grid.leafGridView())) + { + const typename GlobalBasis::LocalFiniteElement& lfe = basis.getLocalFiniteElement(element); FieldVector<double,1> stupidTestPoint(0); std::vector<std::array<typename TargetSpace::EmbeddedTangentVector, TargetSpace::TangentVector::dimension> > values; lfe.localBasis().evaluateFunction(stupidTestPoint, values); for(size_t i=0;i<values.size();i++) { - std::cout<<values[i]<<std::endl; + for (auto v : values[i]) + std::cout << v << " "; + std::cout << std::endl; std::cout<<lfe.localCoefficients().localKey(i)<<std::endl; } //int i = basis.index(*eIt,1); diff --git a/test/harmonicenergytest.cc b/test/harmonicenergytest.cc index 560d6552f121aeadbe64c2d88cfcbc907e8b241f..b0b9466927bf87194a8c862c19577e0f41d7d0e2 100644 --- a/test/harmonicenergytest.cc +++ b/test/harmonicenergytest.cc @@ -2,10 +2,11 @@ #include <dune/grid/uggrid.hh> -#include <dune/localfunctions/lagrange/pqkfactory.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/gfe/unitvector.hh> #include <dune/gfe/harmonicenergystiffness.hh> +#include <dune/gfe/localgeodesicfefunction.hh> #include "multiindex.hh" #include "valuefactory.hh" @@ -16,18 +17,20 @@ typedef UnitVector<double,3> TargetSpace; using namespace Dune; -template <class GridType> -void testEnergy(const GridType* grid, const std::vector<TargetSpace>& coefficients) { +template <class Basis> +void testEnergy(const Basis& basis, const std::vector<TargetSpace>& coefficients) +{ + using GridView = typename Basis::GridView; + GridView gridView = basis.gridView(); - PQkLocalFiniteElementCache<double,double,GridType::dimension,1> feCache; - typedef typename PQkLocalFiniteElementCache<double,double,GridType::dimension,1>::FiniteElementType LocalFiniteElement; - - //LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement,TargetSpace> f(feCache.get(element),corners); + using GeodesicInterpolationRule = LocalGeodesicFEFunction<dim, double, typename Basis::LocalView::Tree::FiniteElement, TargetSpace>; - - HarmonicEnergyLocalStiffness<typename GridType::LeafGridView,LocalFiniteElement,TargetSpace> assembler; + HarmonicEnergyLocalStiffness<Basis,GeodesicInterpolationRule,TargetSpace> assembler; std::vector<TargetSpace> rotatedCoefficients(coefficients.size()); + auto localView = basis.localView(); + localView.bind(*gridView.template begin<0>()); + for (int i=0; i<10; i++) { Rotation<double,3> rotation(FieldVector<double,3>(1), double(i)); @@ -40,68 +43,13 @@ void testEnergy(const GridType* grid, const std::vector<TargetSpace>& coefficien rotatedCoefficients[j] = tmp; } - std::cout << "energy: " << assembler.energy(*grid->template leafbegin<0>(), - feCache.get(grid->template leafbegin<0>()->type()), + std::cout << "energy: " << assembler.energy(localView, rotatedCoefficients) << std::endl; - std::vector<typename TargetSpace::EmbeddedTangentVector> rotatedGradient; - assembler.assembleEmbeddedGradient(*grid->template leafbegin<0>(), - feCache.get(grid->template leafbegin<0>()->type()), - rotatedCoefficients, - rotatedGradient); - - for (size_t j=0; j<coefficients.size(); j++) { - FieldVector<double,3> tmp; - matrix.mtv(rotatedGradient[j], tmp); - std::cout << "gradient: " << tmp << std::endl; - } - } } -template <class GridType> -void testGradientOfEnergy(const GridType* grid, const std::vector<TargetSpace>& coefficients) -{ - PQkLocalFiniteElementCache<double,double,GridType::dimension,1> feCache; - typedef typename PQkLocalFiniteElementCache<double,double,GridType::dimension,1>::FiniteElementType LocalFiniteElement; - - //LocalGeodesicFEFunction<domainDim,double,LocalFiniteElement,TargetSpace> f(feCache.get(element),corners); - HarmonicEnergyLocalStiffness<typename GridType::LeafGridView,LocalFiniteElement,TargetSpace> assembler; - - std::vector<typename TargetSpace::EmbeddedTangentVector> gradient; - assembler.assembleEmbeddedGradient(*grid->template leafbegin<0>(), - feCache.get(grid->template leafbegin<0>()->type()), - coefficients, - gradient); - - //////////////////////////////////////////////////////////////////////////////////////// - // Assemble finite difference approximation of the gradient - //////////////////////////////////////////////////////////////////////////////////////// - - std::vector<typename TargetSpace::EmbeddedTangentVector> fdGradient; - assembler.assembleEmbeddedFDGradient(*grid->template leafbegin<0>(), - feCache.get(grid->template leafbegin<0>()->type()), - coefficients, - fdGradient); - - double diff = 0; - for (size_t i=0; i<fdGradient.size(); i++) - diff = std::max(diff, (gradient[i] - fdGradient[i]).infinity_norm()); - - if (diff > 1e-6) { - - std::cout << "gradient: " << std::endl; - for (size_t i=0; i<gradient.size(); i++) - std::cout << gradient[i] << std::endl; - - std::cout << "fd gradient: " << std::endl; - for (size_t i=0; i<fdGradient.size(); i++) - std::cout << fdGradient[i] << std::endl; - - } - -} template <int domainDim> void testUnitVector3d() @@ -126,10 +74,15 @@ void testUnitVector3d() std::vector<unsigned int> v(domainDim+1); for (int i=0; i<domainDim+1; i++) v[i] = i; - factory.insertElement(GeometryType(GeometryType::simplex,dim), v); + factory.insertElement(GeometryTypes::simplex(dim), v); + + auto grid = std::unique_ptr<const GridType>(factory.createGrid()); + using GridView = typename GridType::LeafGridView; + auto gridView = grid->leafGridView(); - const GridType* grid = factory.createGrid(); - + // A function space basis + using Basis = Functions::LagrangeBasis<GridView,1>; + Basis basis(gridView); // ////////////////////////////////////////////////////////// // Test whether the energy is invariant under isometries @@ -149,8 +102,7 @@ void testUnitVector3d() for (int j=0; j<dim+1; j++) coefficients[j] = testPoints[index[j]]; - testEnergy<GridType>(grid, coefficients); - testGradientOfEnergy(grid, coefficients); + testEnergy<Basis>(basis, coefficients); } diff --git a/test/interillustration.cc b/test/interillustration.cc index 89a0164526dc87b4d337e6c94c422b06cc767034..fdddd9e052c01e3fe861d8e25014dbbfbc19333c 100644 --- a/test/interillustration.cc +++ b/test/interillustration.cc @@ -7,7 +7,7 @@ #include <dune/localfunctions/lagrange/p1.hh> #include <dune/localfunctions/lagrange/p2.hh> -#include <dune/functions/functionspacebases/pq1nodalbasis.hh> +#include <dune/functions/functionspacebases/lagrangebasis.hh> #include <dune/functions/gridfunctions/discretescalarglobalbasisfunction.hh> #include <dune/gfe/unitvector.hh> @@ -143,7 +143,7 @@ void interpolate(const LocalFEFunctionType& localGeodesicFEFunction, // stupid, can't instantiate deformedGrid with a const grid DeformedGridType deformedGrid(const_cast<GridType&>(*grid), deformationFunction); - typedef Functions::PQ1NodalBasis<typename DeformedGridType::LeafGridView > FEBasis; + typedef Functions::LagrangeBasis<typename DeformedGridType::LeafGridView, 1> FEBasis; FEBasis feBasis(deformedGrid.leafGridView()); Functions::DiscreteScalarGlobalBasisFunction<decltype(feBasis),decltype(variation0)> variation0Function(feBasis,variation0); diff --git a/test/localgeodesicfefunctiontest.cc b/test/localgeodesicfefunctiontest.cc index aea15a5580e3e36ef2a85cf7c732dc9a6fd4671b..37f874f4a1e3aef70e84610db620b1cd68cfc7b8 100644 --- a/test/localgeodesicfefunctiontest.cc +++ b/test/localgeodesicfefunctiontest.cc @@ -342,39 +342,34 @@ int main() std::cout << std::setw(15) << std::setprecision(12); - GeometryType element; - //////////////////////////////////////////////////////////////// // Test functions on 1d elements //////////////////////////////////////////////////////////////// - element.makeSimplex(1); - test<RealTuple<double,1>,1>(element); - test<UnitVector<double,2>,1>(element); - test<UnitVector<double,3>,1>(element); - test<Rotation<double,3>,1>(element); - test<RigidBodyMotion<double,3>,1>(element); + test<RealTuple<double,1>,1>(GeometryTypes::simplex(1)); + test<UnitVector<double,2>,1>(GeometryTypes::simplex(1)); + test<UnitVector<double,3>,1>(GeometryTypes::simplex(1)); + test<Rotation<double,3>,1>(GeometryTypes::simplex(1)); + test<RigidBodyMotion<double,3>,1>(GeometryTypes::simplex(1)); //////////////////////////////////////////////////////////////// // Test functions on 2d simplex elements //////////////////////////////////////////////////////////////// - element.makeSimplex(2); - test<RealTuple<double,1>,2>(element); - test<UnitVector<double,2>,2>(element); - test<UnitVector<double,3>,2>(element); - test<Rotation<double,3>,2>(element); - test<RigidBodyMotion<double,3>,2>(element); + test<RealTuple<double,1>,2>(GeometryTypes::simplex(2)); + test<UnitVector<double,2>,2>(GeometryTypes::simplex(2)); + test<UnitVector<double,3>,2>(GeometryTypes::simplex(2)); + test<Rotation<double,3>,2>(GeometryTypes::simplex(2)); + test<RigidBodyMotion<double,3>,2>(GeometryTypes::simplex(2)); //////////////////////////////////////////////////////////////// // Test functions on 2d quadrilateral elements //////////////////////////////////////////////////////////////// - element.makeCube(2); - test<RealTuple<double,1>,2>(element); - test<UnitVector<double,2>,2>(element); - test<UnitVector<double,3>,2>(element); - test<Rotation<double,3>,2>(element); - test<RigidBodyMotion<double,3>,2>(element); + test<RealTuple<double,1>,2>(GeometryTypes::cube(2)); + test<UnitVector<double,2>,2>(GeometryTypes::cube(2)); + test<UnitVector<double,3>,2>(GeometryTypes::cube(2)); + test<Rotation<double,3>,2>(GeometryTypes::cube(2)); + test<RigidBodyMotion<double,3>,2>(GeometryTypes::cube(2)); } diff --git a/test/localgfetestfunctiontest.cc b/test/localgfetestfunctiontest.cc index dee684c72e298c63352e8df82b833b65b00a4489..4b9769c95f7348e66363ed16f9eaa88d8ec5ae38 100644 --- a/test/localgfetestfunctiontest.cc +++ b/test/localgfetestfunctiontest.cc @@ -40,15 +40,12 @@ void test() PQkLocalFiniteElementCache<double,double,domainDim,1> feCache; typedef typename PQkLocalFiniteElementCache<double,double,domainDim,1>::FiniteElementType LocalFiniteElement; - GeometryType simplex; - simplex.makeSimplex(domainDim); - for (int i=0; i<numIndices; i++, ++index) { for (int j=0; j<domainDim+1; j++) coefficients[j] = testPoints[index[j]]; - LocalGfeTestFunctionFiniteElement<LocalFiniteElement,TargetSpace> testFunctionSet(feCache.get(simplex),coefficients); + LocalGfeTestFunctionFiniteElement<LocalFiniteElement,TargetSpace> testFunctionSet(feCache.get(GeometryTypes::simplex(domainDim)),coefficients); FieldVector<double,domainDim> stupidTestPoint(0); @@ -83,7 +80,7 @@ int main() try test<Rotation<double,3>, 1>(); test<Rotation<double,3>, 2>(); -} catch (Exception e) { +} catch (Exception& e) { std::cout << e << std::endl; } diff --git a/test/rodassemblertest.cc b/test/rodassemblertest.cc index 6542a07417e99dd8c3611b6b5516f9c954f707ac..61cb237383027791a494967816d9d4a23ba556be 100644 --- a/test/rodassemblertest.cc +++ b/test/rodassemblertest.cc @@ -1,5 +1,7 @@ #include <config.h> +#include <array> + #include <dune/grid/onedgrid.hh> #include <dune/istl/io.hh> @@ -28,7 +30,7 @@ void infinitesimalVariation(RigidBodyMotion<double,3>& c, double eps, int i) template <class GridType> void strainFD(const std::vector<RigidBodyMotion<double,3> >& x, double pos, - Dune::array<Dune::FieldMatrix<double,2,6>, 6>& fdStrainDerivatives, + std::array<FieldMatrix<double,2,6>, 6>& fdStrainDerivatives, const RodAssembler<GridType,3>& assembler) { assert(x.size()==2); @@ -73,8 +75,8 @@ void strainFD(const std::vector<RigidBodyMotion<double,3> >& x, template <class GridType> void strain2ndOrderFD(const std::vector<RigidBodyMotion<double,3> >& x, double pos, - Dune::array<Dune::Matrix<Dune::FieldMatrix<double,6,6> >, 3>& translationDer, - Dune::array<Dune::Matrix<Dune::FieldMatrix<double,3,3> >, 3>& rotationDer, + std::array<Matrix<FieldMatrix<double,6,6> >, 3>& translationDer, + std::array<Matrix<FieldMatrix<double,3,3> >, 3>& rotationDer, const RodAssembler<GridType,3>& assembler) { assert(x.size()==2); @@ -184,8 +186,8 @@ void strain2ndOrderFD2(const std::vector<RigidBodyMotion<double,3> >& x, double pos, Dune::FieldVector<double,1> shapeGrad[2], Dune::FieldVector<double,1> shapeFunction[2], - Dune::array<Dune::Matrix<Dune::FieldMatrix<double,6,6> >, 3>& translationDer, - Dune::array<Dune::Matrix<Dune::FieldMatrix<double,3,3> >, 3>& rotationDer, + std::array<Matrix<FieldMatrix<double,6,6> >, 3>& translationDer, + std::array<Matrix<FieldMatrix<double,3,3> >, 3>& rotationDer, const RodAssembler<GridType,3>& assembler) { assert(x.size()==2); @@ -214,10 +216,10 @@ void strain2ndOrderFD2(const std::vector<RigidBodyMotion<double,3> >& x, infinitesimalVariation(forwardSolution[k], eps, l+3); infinitesimalVariation(backwardSolution[k], -eps, l+3); - Dune::array<Dune::FieldMatrix<double,2,6>, 6> forwardStrainDer; + std::array<FieldMatrix<double,2,6>, 6> forwardStrainDer; assembler.strainDerivative(forwardSolution, pos, shapeGrad, shapeFunction, forwardStrainDer); - Dune::array<Dune::FieldMatrix<double,2,6>, 6> backwardStrainDer; + std::array<FieldMatrix<double,2,6>, 6> backwardStrainDer; assembler.strainDerivative(backwardSolution, pos, shapeGrad, shapeFunction, backwardStrainDer); for (int i=0; i<2; i++) { @@ -571,7 +573,7 @@ int main (int argc, char *argv[]) try hessianFDCheck(x, hessianMatrix, rodAssembler); // ////////////////////////////// - } catch (Exception e) { + } catch (Exception& e) { std::cout << e << std::endl; diff --git a/test/rotationtest.cc b/test/rotationtest.cc index bf349d2f9c21bc4f762d92fc62df652cb28c2493..ac4f2f6a32aeceb42bd568c64157ad318e595458 100644 --- a/test/rotationtest.cc +++ b/test/rotationtest.cc @@ -395,7 +395,7 @@ int main (int argc, char *argv[]) try return not passed; - } catch (Exception e) { + } catch (Exception& e) { std::cout << e << std::endl; diff --git a/test/targetspacetest.cc b/test/targetspacetest.cc index 820f3e81c8199abf86be9a924fe6ecbac1bb5af0..cadfe4818e3f3c0c8bfce2ff69c7b0e22acaa9cb 100644 --- a/test/targetspacetest.cc +++ b/test/targetspacetest.cc @@ -384,7 +384,7 @@ int main() try // // test<HyperbolicHalfspacePoint<double,2> >(); -} catch (Exception e) { +} catch (Exception& e) { std::cout << e << std::endl;