Newer
Older

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

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/vtk/vtkwriter.hh>
#include <dune/grid/io/file/amirameshreader.hh>
#include <dune/grid/io/file/gmshreader.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>
#include <dune/fufem/functions/vtkbasisgridfunction.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>
#include <dune/gfe/gfedifferencenormsquared.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<double,3> rotation(axis, x.two_norm()*M_PI*3);

Oliver Sander
committed
FieldMatrix<double,3,3> rMat;
rotation.matrix(rMat);
out = rMat[2];
#if 1 // This data seems to have the necessary smoothness to have optimal
// convergence order even for 3rd-order elements
double localX = (x[0] + 2)/4;
double localY = (x[1] + 1)/2;
double angleX = 0.5 * M_PI * sin(M_PI*localX);
double angleY = 0.5 * M_PI * sin(M_PI*localY);
// Rotation matrix around the x axis
FieldMatrix<double,TargetSpace::CoordinateType::dimension,TargetSpace::CoordinateType::dimension> rotationX(0);
rotationX[0][0] = 1;
rotationX[1][1] = cos(angleY);
rotationX[1][2] = -sin(angleY);
rotationX[2][1] = sin(angleY);
rotationX[2][2] = cos(angleY);
// Rotation matrix around the y axis
FieldMatrix<double,TargetSpace::CoordinateType::dimension,TargetSpace::CoordinateType::dimension> rotationY(0);
rotationY[0][0] = cos(angleX);
rotationY[0][2] = -sin(angleX);
rotationY[1][1] = 1;
rotationY[2][0] = sin(angleX);
rotationY[2][2] = cos(angleX);
//angle *= -4*x[1]*(x[1]-1);
TargetSpace::CoordinateType unitVector(0); unitVector[2] = 1;
TargetSpace::CoordinateType tmp;
rotationX.mv(unitVector,tmp);
rotationY.mv(tmp,out);
#endif

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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// ///////////////////////////////////////////
// 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");
// grid file
std::string gridFileName = parameterSet.get<std::string>("gridFile");

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 {
if (gridFileName.rfind(".msh")!=std::string::npos)
referenceGrid = shared_ptr<GridType>(GmshReader<GridType>::read(gridFileName));
else
referenceGrid = shared_ptr<GridType>(AmiraMeshReader<GridType>::read(gridFileName));

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 (size_t j=0; j<referenceSolution.size(); j++)
xEmbedded[j] = referenceSolution[j].globalCoordinates();
// Set up a basis of the underlying fe space
#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());
#if !defined THIRD_ORDER && ! defined SECOND_ORDER
VTKWriter<GridType::LeafGridView> vtkWriter(referenceGrid->leafView());
shared_ptr<VTKBasisGridFunction<FEBasis,BlockVector<TargetSpace::CoordinateType> > > vtkVectorField
= Dune::shared_ptr<VTKBasisGridFunction<FEBasis,BlockVector<TargetSpace::CoordinateType> > >
(new VTKBasisGridFunction<FEBasis,BlockVector<TargetSpace::CoordinateType> >(referenceBasis, xEmbedded, "unit vectors"));
vtkWriter.addVertexData(vtkVectorField);
vtkWriter.write("reference_result");
#endif
// //////////////////////////////////////////////////////////////////////
// Compute mass matrix and laplace matrix to emulate L2 and H1 norms
// //////////////////////////////////////////////////////////////////////
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 {
if (gridFileName.rfind(".msh")!=std::string::npos)
grid = shared_ptr<GridType>(GmshReader<GridType>::read(gridFileName));
else
grid = shared_ptr<GridType>(AmiraMeshReader<GridType>::read(gridFileName));

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());
xEmbedded[j] = solution[j].globalCoordinates();
FEBasis feBasis(grid->leafView());
VTKWriter<GridType::LeafGridView> vtkWriter(grid->leafView());
shared_ptr<VTKBasisGridFunction<FEBasis,BlockVector<TargetSpace::CoordinateType> > > vtkVectorField
= Dune::shared_ptr<VTKBasisGridFunction<FEBasis,BlockVector<TargetSpace::CoordinateType> > >
(new VTKBasisGridFunction<FEBasis,BlockVector<TargetSpace::CoordinateType> >(feBasis, xEmbedded, "unit vectors"));
vtkWriter.addVertexData(vtkVectorField);
vtkWriter.write("harmonic_result_" + numberAsAscii.str());
double newL2 = GFEDifferenceNormSquared<FEBasis,TargetSpace>::compute(*referenceGrid, referenceSolution,
*grid, solution,
&massMatrixLocalAssembler);
newL2 = std::sqrt(newL2);
double newH1 = GFEDifferenceNormSquared<FEBasis,TargetSpace>::compute(*referenceGrid, referenceSolution,
*grid, solution,
&laplaceLocalAssembler);
newH1 = std::sqrt(newH1);

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);
GeodesicFEFunctionAdaptor<FEBasis,TargetSpace>::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 (size_t 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 << "Level: " << i-1 << " vertices: " << xEmbedded.size() << std::endl;
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) << ", new: " << newL2

Oliver Sander
committed
<< std::endl;
std::cout << "Level: " << i-1
<< ", H1 error: " << h1Norm(difference) << ", new: " << newH1

Oliver Sander
committed
<< 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;
}