Newer
Older

Oliver Sander
committed
#include <config.h>
//#define HARMONIC_ENERGY_FD_GRADIENT
//#define HARMONIC_ENERGY_FD_INNER_GRADIENT
#define THIRD_ORDER
//#define SECOND_ORDER

Oliver Sander
committed
const int order = 3;

Oliver Sander
committed

Oliver Sander
committed
#include <dune/common/bitsetvector.hh>
#include <dune/common/parametertree.hh>
#include <dune/common/parametertreeparser.hh>

Oliver Sander
committed
#include <dune/grid/uggrid.hh>
#include <dune/grid/onedgrid.hh>
#include <dune/grid/utility/structuredgridfactory.hh>
#include <dune/grid/io/file/amirameshwriter.hh>
#include <dune/grid/io/file/amirameshreader.hh>

Oliver Sander
committed
#include <dune/fufem/functionspacebases/p1nodalbasis.hh>
#include <dune/fufem/functionspacebases/p2nodalbasis.hh>
#include <dune/fufem/boundarypatch.hh>
#include <dune/fufem/assemblers/operatorassembler.hh>
#include <dune/fufem/assemblers/localassemblers/laplaceassembler.hh>
#include <dune/fufem/assemblers/localassemblers/massassembler.hh>
#include <dune/fufem/functiontools/boundarydofs.hh>

Oliver Sander
committed
#include <dune/fufem/functiontools/basisinterpolator.hh>

Oliver Sander
committed
#include <dune/solvers/solvers/iterativesolver.hh>
#include <dune/solvers/norms/h1seminorm.hh>

Oliver Sander
committed
#include <dune/gfe/unitvector.hh>
#include <dune/gfe/harmonicenergystiffness.hh>
#include <dune/gfe/geodesicfeassembler.hh>
#include <dune/gfe/riemanniantrsolver.hh>
#include <dune/gfe/geodesicfefunctionadaptor.hh>

Oliver Sander
committed
// grid dimension

Oliver Sander
committed
typedef UnitVector<double,3> TargetSpace;

Oliver Sander
committed
typedef std::vector<TargetSpace> SolutionType;
const int blocksize = TargetSpace::TangentVector::dimension;

Oliver Sander
committed
using namespace Dune;
using std::string;

Oliver Sander
committed
struct DirichletFunction
: public Dune::VirtualFunction<FieldVector<double,dim>, TargetSpace::CoordinateType >

Oliver Sander
committed
{
void evaluate(const FieldVector<double, dim>& x, TargetSpace::CoordinateType& out) const {

Oliver Sander
committed

Oliver Sander
committed
FieldVector<double,3> axis;
axis[0] = x[0]; axis[1] = x[1]; axis[2] = 1;
Rotation<3,double> rotation(axis, x.two_norm()*M_PI*3);
FieldMatrix<double,3,3> rMat;
rotation.matrix(rMat);
out = rMat[2];
#endif
double angle = 0.5 * M_PI * x[0];
angle *= -4*x[1]*(x[1]-1);
out = 0;
out[0] = std::cos(angle);
out[1] = std::sin(angle);

Oliver Sander
committed
}
};

Oliver Sander
committed
template <class GridType>
void solve (const shared_ptr<GridType>& grid,
SolutionType& x,
int numLevels,
const ParameterTree& parameters)

Oliver Sander
committed
{
// read solver setting
const double innerTolerance = parameters.get<double>("innerTolerance");
const double tolerance = parameters.get<double>("tolerance");
const int maxTrustRegionSteps = parameters.get<int>("maxTrustRegionSteps");
const double initialTrustRegionRadius = parameters.get<double>("initialTrustRegionRadius");
const int multigridIterations = parameters.get<int>("numIt");
// /////////////////////////////////////////
// Read Dirichlet values
// /////////////////////////////////////////
BitSetVector<1> allNodes(grid->size(dim));
allNodes.setAll();
BoundaryPatch<typename GridType::LeafGridView> dirichletBoundary(grid->leafView(), allNodes);

Oliver Sander
committed
#if defined THIRD_ORDER
typedef P3NodalBasis<typename GridType::LeafGridView,double> FEBasis;
#elif defined SECOND_ORDER
typedef P2NodalBasis<typename GridType::LeafGridView,double> FEBasis;
#else
typedef P1NodalBasis<typename GridType::LeafGridView,double> FEBasis;
#endif
FEBasis feBasis(grid->leafView());
BitSetVector<blocksize> dirichletNodes;
constructBoundaryDofs(dirichletBoundary,feBasis,dirichletNodes);

Oliver Sander
committed
// //////////////////////////
// Initial solution
// //////////////////////////

Oliver Sander
committed
BlockVector<TargetSpace::CoordinateType> dirichletFunctionValues;

Oliver Sander
committed
DirichletFunction dirichletFunction;
Functions::interpolate(feBasis, dirichletFunctionValues, dirichletFunction);

Oliver Sander
committed
TargetSpace::CoordinateType innerValue(0);

Oliver Sander
committed
innerValue[0] = 1;
innerValue[1] = 0;
for (size_t i=0; i<x.size(); i++)
x[i] = (dirichletNodes[i][0]) ? dirichletFunctionValues[i] : innerValue;

Oliver Sander
committed
// ////////////////////////////////////////////////////////////
// Create an assembler for the Harmonic Energy Functional
// ////////////////////////////////////////////////////////////
HarmonicEnergyLocalStiffness<typename GridType::LeafGridView,typename FEBasis::LocalFiniteElement, TargetSpace> harmonicEnergyLocalStiffness;
GeodesicFEAssembler<FEBasis,TargetSpace> assembler(grid->leafView(),
&harmonicEnergyLocalStiffness);

Oliver Sander
committed
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// ///////////////////////////////////////////
// Create a solver for the rod problem
// ///////////////////////////////////////////
RiemannianTrustRegionSolver<GridType,TargetSpace> solver;
solver.setup(*grid,
&assembler,
x,
dirichletNodes,
tolerance,
maxTrustRegionSteps,
initialTrustRegionRadius,
multigridIterations,
innerTolerance,
1, 3, 3,
100, // iterations of the base solver
1e-8, // base tolerance
false); // instrumentation
// /////////////////////////////////////////////////////
// Solve!
// /////////////////////////////////////////////////////
solver.setInitialSolution(x);
solver.solve();
x = solver.getSol();
}
int main (int argc, char *argv[]) try
{
// parse data file

Oliver Sander
committed
if (argc==2)
ParameterTreeParser::readINITree(argv[1], parameterSet);

Oliver Sander
committed
else
ParameterTreeParser::readINITree("harmonicmaps-eoc.parset", parameterSet);

Oliver Sander
committed
// read solver settings
const int numLevels = parameterSet.get<int>("numLevels");
const int baseIterations = parameterSet.get<int>("baseIt");
const double baseTolerance = parameterSet.get<double>("baseTolerance");

Oliver Sander
committed
const int numBaseElements = parameterSet.get<int>("numBaseElements");
FieldVector<double,dim> lowerLeft = parameterSet.get<FieldVector<double,dim> >("lowerLeft");
FieldVector<double,dim> upperRight = parameterSet.get<FieldVector<double,dim> >("upperRight");

Oliver Sander
committed
// ///////////////////////////////////////////////////////////
// First compute the 'exact' solution on a very fine grid
// ///////////////////////////////////////////////////////////
typedef std::conditional<dim==1,OneDGrid,UGGrid<dim> >::type GridType;
// Create the reference grid
shared_ptr<GridType> referenceGrid;
if (parameterSet.get<std::string>("gridType")=="structured") {
array<unsigned int,dim> elements;
elements.fill(numBaseElements);
referenceGrid = StructuredGridFactory<GridType>::createSimplexGrid(lowerLeft,
upperRight,
elements);
} else {
referenceGrid = shared_ptr<GridType>(AmiraMeshReader<GridType>::read(parameterSet.get<std::string>("gridFile")));
}

Oliver Sander
committed
referenceGrid->globalRefine(numLevels-1);
// Solve the rod Dirichlet problem
SolutionType referenceSolution;
solve(referenceGrid, referenceSolution, numLevels, parameterSet);
BlockVector<TargetSpace::CoordinateType> xEmbedded(referenceSolution.size());
for (int j=0; j<referenceSolution.size(); j++)
xEmbedded[j] = referenceSolution[j].globalCoordinates();
#if !defined THIRD_ORDER && ! defined SECOND_ORDER
LeafAmiraMeshWriter<GridType> amiramesh;
amiramesh.addGrid(referenceGrid->leafView());
amiramesh.addVertexData(xEmbedded, referenceGrid->leafView());
amiramesh.write("reference_result.am");

Oliver Sander
committed
// //////////////////////////////////////////////////////////////////////
// Compute mass matrix and laplace matrix to emulate L2 and H1 norms
// //////////////////////////////////////////////////////////////////////
#ifdef THIRD_ORDER
typedef P3NodalBasis<GridType::LeafGridView,double> FEBasis;
#elif defined SECOND_ORDER
typedef P2NodalBasis<GridType::LeafGridView,double> FEBasis;
#else

Oliver Sander
committed
typedef P1NodalBasis<GridType::LeafGridView,double> FEBasis;
FEBasis referenceBasis(referenceGrid->leafView());
OperatorAssembler<FEBasis,FEBasis> operatorAssembler(referenceBasis, referenceBasis);

Oliver Sander
committed

Oliver Sander
committed
LaplaceAssembler<GridType, FEBasis::LocalFiniteElement, FEBasis::LocalFiniteElement> laplaceLocalAssembler(2*(order-1));
MassAssembler<GridType, FEBasis::LocalFiniteElement, FEBasis::LocalFiniteElement> massMatrixLocalAssembler(2*order);

Oliver Sander
committed
typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> > ScalarMatrixType;
ScalarMatrixType laplace, massMatrix;
operatorAssembler.assemble(laplaceLocalAssembler, laplace);
operatorAssembler.assemble(massMatrixLocalAssembler, massMatrix);

Oliver Sander
committed
// ///////////////////////////////////////////////////////////
// Compute on all coarser levels, and compare
// ///////////////////////////////////////////////////////////
std::ofstream logFile("harmonicmaps-eoc.results");
logFile << "# mesh size, max-norm, L2-norm, h1-seminorm" << std::endl;
for (int i=1; i<numLevels; i++) {

Oliver Sander
committed
shared_ptr<GridType> grid;
if (parameterSet.get<std::string>("gridType")=="structured") {
array<unsigned int,dim> elements;
elements.fill(numBaseElements);
grid = StructuredGridFactory<GridType>::createSimplexGrid(lowerLeft,
upperRight,
elements);
} else {
grid = shared_ptr<GridType>(AmiraMeshReader<GridType>::read(parameterSet.get<std::string>("gridFile")));
}

Oliver Sander
committed
grid->globalRefine(i-1);
// compute again
SolutionType solution;
solve(grid, solution, i, parameterSet);
// write solution
std::stringstream numberAsAscii;
numberAsAscii << i;
BlockVector<TargetSpace::CoordinateType> xEmbedded(solution.size());
for (int j=0; j<solution.size(); j++)
xEmbedded[j] = solution[j].globalCoordinates();
#if ! defined THIRD_ORDER && ! defined SECOND_ORDER
LeafAmiraMeshWriter<GridType> amiramesh;
amiramesh.addGrid(grid->leafView());
amiramesh.addVertexData(xEmbedded, grid->leafView());
amiramesh.write("harmonic_result_" + numberAsAscii.str() + ".am");

Oliver Sander
committed
// Prolong solution to the very finest grid
for (int j=i; j<numLevels; j++) {
FEBasis basis(grid->leafView());
#if defined THIRD_ORDER || defined SECOND_ORDER
GeodesicFEFunctionAdaptor<FEBasis,TargetSpace>::higherOrderGFEFunctionAdaptor<order>(basis, *grid, solution);
#else
geodesicFEFunctionAdaptor(*grid, solution);
}
// Interpret TargetSpace as isometrically embedded into an R^m, because this is
// how the corresponding Sobolev spaces are defined.
BlockVector<TargetSpace::CoordinateType> difference(referenceSolution.size());
for (int j=0; j<referenceSolution.size(); j++)
difference[j] = solution[j].globalCoordinates() - referenceSolution[j].globalCoordinates();

Oliver Sander
committed
H1SemiNorm< BlockVector<TargetSpace::CoordinateType> > h1Norm(laplace);
H1SemiNorm< BlockVector<TargetSpace::CoordinateType> > l2Norm(massMatrix);

Oliver Sander
committed
// Compute max-norm difference
std::cout << "h: " << std::pow(0.5, i-1) << std::endl;

Oliver Sander
committed
std::cout << "Level: " << i-1
<< ", max-norm error: " << difference.infinity_norm()
<< std::endl;
std::cout << "Level: " << i-1
<< ", L2 error: " << l2Norm(difference)
<< std::endl;
std::cout << "Level: " << i-1
<< ", H1 error: " << h1Norm(difference)
<< std::endl;
logFile << std::pow(0.5, i-1) << " " << difference.infinity_norm()
<< " " << l2Norm(difference)
<< " " << h1Norm(difference)
<< std::endl;

Oliver Sander
committed
}
} catch (Exception e) {
std::cout << e << std::endl;
}