Newer
Older
#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 <dune/common/typetraits.hh>
#include <dune/common/bitsetvector.hh>
#include <dune/common/version.hh>
#include <dune/grid/uggrid.hh>
#include <dune/grid/io/file/gmshreader.hh>
#include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
#include <dune/functions/functionspacebases/lagrangebasis.hh>
#include <dune/functions/functionspacebases/powerbasis.hh>
#include <dune/functions/functionspacebases/interpolate.hh>
#include <dune/fufem/boundarypatch.hh>
#include <dune/fufem/functiontools/boundarydofs.hh>
#include <dune/gfe/localgeodesicfefunction.hh>
#include <dune/gfe/localprojectedfefunction.hh>
#include <dune/gfe/assemblers/localintegralstiffness.hh>
#include <dune/gfe/assemblers/geodesicfeassembler.hh>
#include <dune/gfe/assemblers/localintegralenergy.hh>
#include <dune/gfe/densities/harmonicdensity.hh>
#include <dune/gfe/riemanniantrsolver.hh>
#include <dune/gfe/spaces/unitvector.hh>
// grid dimension
const int dim = 2;
// Image space of the geodesic fe functions
typedef UnitVector<double,3> TargetSpace;
const int order = 1;
using namespace Dune;
int main (int argc, char *argv[])
{
MPIHelper::instance(argc, argv);
using SolutionType = std::vector<TargetSpace>;
// read problem settings
const int numLevels = 4;
// read solver settings
const double tolerance = 1e-6;
const int maxTrustRegionSteps = 1000;
const double initialTrustRegionRadius = 0.25;
const int multigridIterations = 200;
const int baseIterations = 100;
const double mgTolerance = 1e-10;
const double baseTolerance = 1e-8;
// ///////////////////////////////////////
// Create the grid
// ///////////////////////////////////////
using GridType = UGGrid<dim>;
std::shared_ptr<GridType> grid = GmshReader<GridType>::read("grids/irregular-square.msh");
grid->globalRefine(numLevels-1);
using GridView = GridType::LeafGridView;
GridView gridView = grid->leafGridView();
//////////////////////////////////////////////////////////////////////////////////
// Construct the scalar function space basis corresponding to the GFE space
//////////////////////////////////////////////////////////////////////////////////
using FEBasis = Functions::LagrangeBasis<GridView, order>;
FEBasis feBasis(gridView);
SolutionType x(feBasis.size());
using namespace Functions::BasisFactory;
// A basis for the embedding space
auto powerBasis = makeBasis(
gridView,
power<TargetSpace::CoordinateType::dimension>(
lagrange<order>(),
blockedInterleaved()
// A basis for the tangent space
auto tangentBasis = makeBasis(
gridView,
power<TargetSpace::TangentVector::dimension>(
lagrange<order>(),
blockedInterleaved()
///////////////////////////////////////////
// Determine Dirichlet values
///////////////////////////////////////////
BitSetVector<1> dirichletVertices(gridView.size(dim), false);
const GridView::IndexSet& indexSet = gridView.indexSet();
// Make predicate function that computes which vertices are on the Dirichlet boundary,
// based on the vertex positions.
auto dirichletVerticesPredicate = [](FieldVector<double,dim> x)
{
return (x[0] < -4.9999 or x[0] > 4.9999 or x[1] < -4.9999 or x[1] > 4.9999);
};
for (auto&& vertex : vertices(gridView))
{
bool isDirichlet = dirichletVerticesPredicate(vertex.geometry().corner(0));
dirichletVertices[indexSet.index(vertex)] = isDirichlet;
}
BoundaryPatch<GridView> dirichletBoundary(gridView, dirichletVertices);
BitSetVector<TargetSpace::TangentVector::dimension> dirichletNodes(powerBasis.size(), false);
#if DUNE_VERSION_GTE(DUNE_FUFEM, 2, 10)
Fufem::markBoundaryPatchDofs(dirichletBoundary,tangentBasis,dirichletNodes);
#else
constructBoundaryDofs(dirichletBoundary,tangentBasis,dirichletNodes);
////////////////////////////
// Initial iterate
////////////////////////////
// The inverse stereographic projection through the north pole
auto initialIterateFunction = [](FieldVector<double,dim> x) -> TargetSpace::CoordinateType
{
auto normSquared = x.two_norm2();
return {2*x[0] / (normSquared+1), 2*x[1] / (normSquared+1), (normSquared-1)/ (normSquared+1)};
};
std::vector<TargetSpace::CoordinateType> v;
Dune::Functions::interpolate(powerBasis, v, initialIterateFunction);
for (size_t i=0; i<x.size(); i++)
x[i] = v[i];
//////////////////////////////////////////////////////////////
// Create an assembler for the Harmonic Energy Functional
//////////////////////////////////////////////////////////////
#if GEODESICINTERPOLATION
using InterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace>;
#else
#if CONFORMING
using InterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace,true>;
using InterpolationRule = GFE::LocalProjectedFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace,false>;
#endif
#endif
auto harmonicDensity = std::make_shared<GFE::HarmonicDensity<GridType::Codim<0>::Entity::Geometry::LocalCoordinate, TargetSpace> >();
GFE::LocalIntegralStiffness<FEBasis,InterpolationRule,TargetSpace> localGFEADOLCStiffness(harmonicDensity);
GeodesicFEAssembler<FEBasis,TargetSpace> assembler(feBasis, localGFEADOLCStiffness);
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
///////////////////////////////////////////////////
// Create a Riemannian trust-region solver
///////////////////////////////////////////////////
RiemannianTrustRegionSolver<FEBasis,TargetSpace> solver;
solver.setup(*grid,
&assembler,
x,
dirichletNodes,
tolerance,
maxTrustRegionSteps,
initialTrustRegionRadius,
multigridIterations,
mgTolerance,
3, 3, 1, // Multigrid V-cycle
baseIterations,
baseTolerance,
false); // Do not write intermediate iterates
///////////////////////////////////////////////////////
// Solve!
///////////////////////////////////////////////////////
solver.setInitialIterate(x);
solver.solve();
x = solver.getSol();
#if GEODESICINTERPOLATION
std::size_t expectedFinalIteration = 8;
#else
#if CONFORMING
std::size_t expectedFinalIteration = 10;
#else
std::size_t expectedFinalIteration = 6;
#endif
#endif
if (solver.getStatistics().finalIteration != expectedFinalIteration)
{
std::cerr << "Trust-region solver did " << solver.getStatistics().finalIteration+1
<< " iterations, instead of the expected '" << expectedFinalIteration+1 << "'!" << std::endl;
return 1;
#if GEODESICINTERPOLATION
double expectedEnergy = 12.3154833;
#else
#if CONFORMING
double expectedEnergy = 12.2927849;
#else
double expectedEnergy = 0.436857464;
#endif
#endif
if ( std::abs(solver.getStatistics().finalEnergy - expectedEnergy) > 1e-7)
{
std::cerr << std::setprecision(9);
std::cerr << "Final energy is " << solver.getStatistics().finalEnergy
<< " but '" << expectedEnergy << "' was expected!" << std::endl;
return 1;