Newer
Older
#define MIXED_SPACE 0
//#define PROJECTED_INTERPOLATION
#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>

Oliver Sander
committed
#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>
#include <dune/grid/io/file/gmshreader.hh>
#if HAVE_DUNE_FOAMGRID
#include <dune/foamgrid/foamgrid.hh>
#endif
#include <dune/functions/functionspacebases/lagrangebasis.hh>
#include <dune/functions/functionspacebases/compositebasis.hh>
#include <dune/functions/functionspacebases/powerbasis.hh>
#include <dune/fufem/functiontools/boundarydofs.hh>
#include <dune/fufem/dunepython.hh>
#include <dune/solvers/solvers/iterativesolver.hh>
#include <dune/solvers/norms/energynorm.hh>
#include <dune/gfe/localgeodesicfefunction.hh>
#include <dune/gfe/localprojectedfefunction.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>
#include <dune/gfe/cosseratvtkreader.hh>
#include <dune/gfe/geodesicfeassembler.hh>
#include <dune/gfe/embeddedglobalgfefunction.hh>
#include <dune/gfe/mixedgfeassembler.hh>
#if MIXED_SPACE
#include <dune/gfe/mixedriemanniantrsolver.hh>
#else
#include <dune/gfe/geodesicfeassemblerwrapper.hh>
#include <dune/gfe/riemannianpnsolver.hh>
#include <dune/gfe/riemanniantrsolver.hh>
#include <dune/gfe/rigidbodymotion.hh>
#endif
#if HAVE_DUNE_VTK
#include <dune/vtk/vtkreader.hh>
#endif

Lisa Julia Nebel
committed
// grid dimension
const int dim = 2;
const int dimworld = 2;
// Order of the approximation space for the displacement
const int displacementOrder = 2;
// Order of the approximation space for the microrotations
const int rotationOrder = 2;
#if !MIXED_SPACE
static_assert(displacementOrder==rotationOrder, "displacement and rotation order do not match!");
// Image space of the geodesic fe functions
using TargetSpace = RigidBodyMotion<double, 3>;
using namespace Dune;
int main (int argc, char *argv[]) try
{
// initialize MPI, finalize is done automatically on exit

Oliver Sander
committed
Dune::MPIHelper& mpiHelper = MPIHelper::instance(argc, argv);
if (mpiHelper.rank()==0) {
std::cout << "DISPLACEMENTORDER = " << displacementOrder << ", ROTATIONORDER = " << rotationOrder << std::endl;
std::cout << "dim = " << dim << ", dimworld = " << dimworld << std::endl;
#if MIXED_SPACE
std::cout << "MIXED_SPACE = 1" << std::endl;
#else
std::cout << "MIXED_SPACE = 0" << std::endl;
#endif
}
// 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 << "import os"
<< std::endl << "sys.path.append(os.getcwd() + '/../../problems/')"
<< std::endl;
using namespace TypeTree::Indices;
using SolutionType = TupleVector<std::vector<RealTuple<double,3> >,
std::vector<Rotation<double,3> > >;
// parse data file
ParameterTree parameterSet;
DUNE_THROW(Exception, "Usage: ./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 maxSolverSteps = parameterSet.get<int>("maxSolverSteps");
const double initialRegularization = parameterSet.get<double>("initialRegularization", 1000);
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
// ///////////////////////////////////////
#if HAVE_DUNE_FOAMGRID
typedef std::conditional<dim==dimworld,UGGrid<dim>, FoamGrid<dim,dimworld> >::type GridType;
#else
static_assert(dim==dimworld, "FoamGrid needs to be installed to allow problems with dim != dimworld.");
typedef UGGrid<dim> GridType;
#endif
std::shared_ptr<GridType> grid;
FieldVector<double,dimworld> lower(0), upper(1);
std::string structuredGridType = parameterSet["structuredGrid"];
if (structuredGridType == "cube") {
if (dim!=dimworld)
DUNE_THROW(GridError, "Please use FoamGrid and read in a grid for problems with dim != dimworld.");
lower = parameterSet.get<FieldVector<double,dimworld> >("lower");
upper = parameterSet.get<FieldVector<double,dimworld> >("upper");

Oliver Sander
committed
auto elements = parameterSet.get<std::array<unsigned int,dim> >("elements");
grid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements);

Oliver Sander
committed
} else {
std::string path = parameterSet.get<std::string>("path");
std::string gridFile = parameterSet.get<std::string>("gridFile");
// Guess the grid file format by looking at the file name suffix
auto dotPos = gridFile.rfind('.');
if (dotPos == std::string::npos)
DUNE_THROW(IOError, "Could not determine grid input file format");
std::string suffix = gridFile.substr(dotPos, gridFile.length()-dotPos);
if (suffix == ".msh")
grid = std::shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + gridFile));
else if (suffix == ".vtu" or suffix == ".vtp")
#if HAVE_DUNE_VTK
grid = VtkReader<GridType>::createGridFromFile(path + "/" + gridFile);
#else
DUNE_THROW(NotImplemented, "Please install dune-vtk for VTK reading support!");
#endif

Oliver Sander
committed
}
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::BasisFactory;
const int dimRotation = Rotation<double,dim>::embeddedDim;
auto compositeBasis = makeBasis(
gridView,
composite(
power<dim>(
lagrange<displacementOrder>()
),
power<dimRotation>(
lagrange<rotationOrder>()
)
));
using CompositeBasis = decltype(compositeBasis);
auto deformationPowerBasis = makeBasis(
gridView,
power<3>(
lagrange<displacementOrder>()
));

Lisa Julia Nebel
committed
auto orientationPowerBasis = makeBasis(
gridView,
power<3>(
power<3>(
lagrange<rotationOrder>()
)
));
typedef Dune::Functions::LagrangeBasis<GridView,displacementOrder> DeformationFEBasis;
typedef Dune::Functions::LagrangeBasis<GridView,rotationOrder> OrientationFEBasis;
DeformationFEBasis deformationFEBasis(gridView);
OrientationFEBasis orientationFEBasis(gridView);
// /////////////////////////////////////////
// Read Dirichlet values
// /////////////////////////////////////////
BitSetVector<1> dirichletVertices(gridView.size(dim), false);
BitSetVector<1> neumannVertices(gridView.size(dim), false);
const GridView::IndexSet& indexSet = gridView.indexSet();

Oliver Sander
committed
// 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(")");
auto pythonDirichletVertices = Python::make_function<bool>(Python::evaluate(lambda));

Oliver Sander
committed
// Same for the Neumann boundary
lambda = std::string("lambda x: (") + parameterSet.get<std::string>("neumannVerticesPredicate", "0") + std::string(")");
auto pythonNeumannVertices = Python::make_function<bool>(Python::evaluate(lambda));

Oliver Sander
committed
for (auto&& vertex : vertices(gridView))
{
bool isDirichlet = pythonDirichletVertices(vertex.geometry().corner(0));
dirichletVertices[indexSet.index(vertex)] = isDirichlet;
bool isNeumann = pythonNeumannVertices(vertex.geometry().corner(0));
neumannVertices[indexSet.index(vertex)] = isNeumann;
BoundaryPatch<GridView> dirichletBoundary(gridView, dirichletVertices);
BoundaryPatch<GridView> neumannBoundary(gridView, neumannVertices);

Lisa Julia Nebel
committed
std::cout << "On rank " << mpiHelper.rank() << ": Dirichlet boundary has " << dirichletBoundary.numFaces()
<< " faces and " << dirichletVertices.count() << " nodes.\n";
std::cout << "On rank " << mpiHelper.rank() << ": Neumann boundary has " << neumannBoundary.numFaces() << " faces.\n";
BitSetVector<1> deformationDirichletNodes(deformationFEBasis.size(), false);
constructBoundaryDofs(dirichletBoundary,deformationFEBasis,deformationDirichletNodes);
BitSetVector<1> neumannNodes(deformationFEBasis.size(), false);
constructBoundaryDofs(neumannBoundary,deformationFEBasis,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,orientationFEBasis,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(compositeBasis.size({0}));
lambda = std::string("lambda x: (") + parameterSet.get<std::string>("initialDeformation") + std::string(")");
auto pythonInitialDeformation = Python::make_function<FieldVector<double,3> >(Python::evaluate(lambda));
std::vector<FieldVector<double,3> > v;
Functions::interpolate(deformationPowerBasis, v, pythonInitialDeformation);
for (size_t i=0; i<x[_0].size(); i++)
x[_0][i] = v[i];
x[_1].resize(compositeBasis.size({1}));
#if !MIXED_SPACE
if (parameterSet.hasKey("startFromFile"))
{
std::shared_ptr<GridType> initialIterateGrid;
if (parameterSet.get<bool>("structuredGrid"))
{
std::array<unsigned int,dim> elements = parameterSet.get<std::array<unsigned int,dim> >("elements");
initialIterateGrid = StructuredGridFactory<GridType>::createCubeGrid(lower, upper, elements);
}
else
{
std::string path = parameterSet.get<std::string>("path");
std::string initialIterateGridFilename = parameterSet.get<std::string>("initialIterateGridFilename");
initialIterateGrid = std::shared_ptr<GridType>(GmshReader<GridType>::read(path + "/" + initialIterateGridFilename));
}
std::vector<TargetSpace> initialIterate;
GFE::CosseratVTKReader::read(initialIterate, parameterSet.get<std::string>("initialIterateFilename"));
typedef Dune::Functions::LagrangeBasis<typename GridType::LeafGridView, 2> InitialBasis;
InitialBasis initialBasis(initialIterateGrid->leafGridView());
#ifdef PROJECTED_INTERPOLATION
using LocalInterpolationRule = GFE::LocalProjectedFEFunction<dim, double, DeformationFEBasis::LocalView::Tree::FiniteElement, TargetSpace>;
using LocalInterpolationRule = LocalGeodesicFEFunction<dim, double, DeformationFEBasis::LocalView::Tree::FiniteElement, TargetSpace>;
#endif
GFE::EmbeddedGlobalGFEFunction<InitialBasis,LocalInterpolationRule,TargetSpace> initialFunction(initialBasis,initialIterate);
auto powerBasis = makeBasis(
gridView,
power<7>(
lagrange<displacementOrder>()
));
std::vector<FieldVector<double,7> > v;
//TODO: Interpolate does not work with an GFE:EmbeddedGlobalGFEFunction
//Dune::Functions::interpolate(powerBasis,v,initialFunction);
for (size_t i=0; i<x.size(); i++) {
auto vTargetSpace = TargetSpace(v[i]);
x[_0][i] = vTargetSpace.r;
x[_1][i] = vTargetSpace.q;
}
////////////////////////////////////////////////////////
// Main homotopy loop
////////////////////////////////////////////////////////
// Output initial iterate (of homotopy loop)
BlockVector<FieldVector<double,3> > identity(compositeBasis.size({0}));
Dune::Functions::interpolate(deformationPowerBasis, identity, [&](FieldVector<double,dimworld> x){ return x;});
BlockVector<FieldVector<double,3> > displacement(compositeBasis.size({0}));
if (dim == dimworld) {
CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,x[_0],
orientationFEBasis,x[_1],
resultPath + "mixed-cosserat_homotopy_0");
} else {
#if MIXED_SPACE
for (int i = 0; i < displacement.size(); i++) {
for (int j = 0; j < 3; j++)
displacement[i][j] = x[_0][i][j];
displacement[i] -= identity[i];
}
auto displacementFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3>>(deformationPowerBasis, displacement);
SubsamplingVTKWriter<GridView> vtkWriter(gridView, Dune::refinementLevels(0));
vtkWriter.addVertexData(displacementFunction, VTK::FieldInfo("displacement", VTK::FieldInfo::Type::scalar, dimworld));
vtkWriter.write(resultPath + "mixed-cosserat_homotopy_0");
CosseratVTKWriter<GridType>::write<DeformationFEBasis>(deformationFEBasis, x, resultPath + "cosserat_homotopy_0");
#endif
}
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");
FieldVector<double,3> neumannValues {0,0,0};
if (parameterSet.hasKey("neumannValues"))
neumannValues = parameterSet.get<FieldVector<double,3> >("neumannValues");

Lisa Julia Nebel
committed
auto neumannFunction = [&]( FieldVector<double,dimworld> ) {
auto nV = neumannValues;
nV *= homotopyParameter;
return nV;
};
FieldVector<double,3> volumeLoadValues {0,0,0};
volumeLoadValues = parameterSet.get<FieldVector<double,3> >("volumeLoad");

Lisa Julia Nebel
committed
auto volumeLoad = [&]( FieldVector<double,dimworld>) {
auto vL = volumeLoadValues;
vL *= homotopyParameter;
return vL;
};
if (mpiHelper.rank() == 0) {
std::cout << "Material parameters:" << std::endl;
materialParameters.report();
}
////////////////////////////////////////////////////////
// Set Dirichlet values
////////////////////////////////////////////////////////
Python::Reference dirichletValuesClass = Python::import(parameterSet.get<std::string>("problem") + "-dirichlet-values");

Oliver Sander
committed
Python::Callable C = dirichletValuesClass.get("DirichletValues");

Oliver Sander
committed
// Call a constructor.
Python::Reference dirichletValuesPythonObject = C(homotopyParameter);

Oliver Sander
committed
// Extract object member functions as Dune functions
auto deformationDirichletValues = Python::make_function<FieldVector<double,3> > (dirichletValuesPythonObject.get("deformation"));
auto orientationDirichletValues = Python::make_function<FieldMatrix<double,3,3> > (dirichletValuesPythonObject.get("orientation"));
BlockVector<FieldVector<double,3> > ddV;
Dune::Functions::interpolate(deformationPowerBasis, ddV, deformationDirichletValues, deformationDirichletDofs);
BlockVector<FieldMatrix<double,3,3> > dOV;

Lisa Julia Nebel
committed
Dune::Functions::interpolate(orientationPowerBasis, dOV, orientationDirichletValues);
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
for (int i = 0; i < compositeBasis.size({0}); i++) {
if (deformationDirichletDofs[i][0])
x[_0][i] = ddV[i];
}
for (int i = 0; i < compositeBasis.size({1}); i++)
if (orientationDirichletDofs[i][0])
x[_1][i].set(dOV[i]);
if (dim==dimworld) {
CosseratEnergyLocalStiffness<CompositeBasis, 3,adouble> localCosseratEnergy(materialParameters,
&neumannBoundary,
neumannFunction,
volumeLoad);
MixedLocalGFEADOLCStiffness<CompositeBasis,
RealTuple<double,3>,
Rotation<double,3> > localGFEADOLCStiffness(&localCosseratEnergy);
MixedGFEAssembler<CompositeBasis,
RealTuple<double,3>,
Rotation<double,3> > mixedAssembler(compositeBasis, &localGFEADOLCStiffness);
#if MIXED_SPACE
MixedRiemannianTrustRegionSolver<GridType,
CompositeBasis,
DeformationFEBasis, RealTuple<double,3>,
OrientationFEBasis, Rotation<double,3> > solver;
solver.setup(*grid,
&mixedAssembler,
deformationFEBasis,
orientationFEBasis,
x,
deformationDirichletDofs,
orientationDirichletDofs, tolerance,
initialTrustRegionRadius,
multigridIterations,
mgTolerance,
mu, nu1, nu2,
baseIterations,
baseTolerance,
instrumented);
solver.setScaling(parameterSet.get<FieldVector<double,6> >("trustRegionScaling"));
solver.setInitialIterate(x);
solver.solve();
x = solver.getSol();
//The MixedRiemannianTrustRegionSolver can treat the Displacement and Orientation Space as separate ones
//The RiemannianTrustRegionSolver can only treat the Displacement and Rotation together in a RigidBodyMotion
//Therefore, x and the dirichletDofs are converted to a RigidBodyMotion structure, as well as the Hessian and Gradient that are returned by the assembler
std::vector<TargetSpace> xTargetSpace(compositeBasis.size({0}));
BitSetVector<TargetSpace::TangentVector::dimension> dirichletDofsTargetSpace(compositeBasis.size({0}), false);
for (int i = 0; i < compositeBasis.size({0}); i++) {
for (int j = 0; j < 3; j ++) { // Displacement part
xTargetSpace[i].r[j] = x[_0][i][j];
dirichletDofsTargetSpace[i][j] = deformationDirichletDofs[i][j];
}
xTargetSpace[i].q = x[_1][i]; // Rotation part
for (int j = 3; j < TargetSpace::TangentVector::dimension; j ++)
dirichletDofsTargetSpace[i][j] = orientationDirichletDofs[i][j-3];
}
using GFEAssemblerWrapper = Dune::GFE::GeodesicFEAssemblerWrapper<CompositeBasis, DeformationFEBasis, TargetSpace, RealTuple<double, 3>, Rotation<double,3>>;
GFEAssemblerWrapper assembler(&mixedAssembler, deformationFEBasis);

Lisa Julia Nebel
committed
if (parameterSet.get<std::string>("solvertype", "trustRegion") == "trustRegion") {
RiemannianTrustRegionSolver<DeformationFEBasis, TargetSpace, GFEAssemblerWrapper> solver;
solver.setup(*grid,
&assembler,
xTargetSpace,
dirichletDofsTargetSpace,
tolerance,
initialTrustRegionRadius,
multigridIterations,
mgTolerance,
mu, nu1, nu2,
baseIterations,
baseTolerance,
instrumented);
solver.setScaling(parameterSet.get<FieldVector<double,6> >("trustRegionScaling"));
solver.setInitialIterate(xTargetSpace);
solver.solve();
xTargetSpace = solver.getSol();

Lisa Julia Nebel
committed
} else {
RiemannianProximalNewtonSolver<DeformationFEBasis, TargetSpace, GFEAssemblerWrapper> solver;
solver.setup(*grid,
&assembler,
xTargetSpace,
dirichletDofsTargetSpace,
tolerance,
maxSolverSteps,
initialRegularization,
instrumented);
solver.setInitialIterate(xTargetSpace);
solver.solve();
xTargetSpace = solver.getSol();
}
for (int i = 0; i < xTargetSpace.size(); i++) {
x[_0][i] = xTargetSpace[i].r;
x[_1][i] = xTargetSpace[i].q;
}
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
} else {
#if MIXED_SPACE
DUNE_THROW(Exception, "Problems with dim != dimworld do not work for MIXED_SPACE = 1!");
#else
std::shared_ptr<LocalGeodesicFEADOLCStiffness<DeformationFEBasis, TargetSpace>> localGFEADOLCStiffness;
NonplanarCosseratShellEnergy<DeformationFEBasis, 3, adouble> localCosseratEnergyPlanar(materialParameters,
nullptr,
&neumannBoundary,
neumannFunction,
volumeLoad);
localGFEADOLCStiffness = std::make_shared<LocalGeodesicFEADOLCStiffness<DeformationFEBasis, TargetSpace>>(&localCosseratEnergyPlanar);
GeodesicFEAssembler<DeformationFEBasis,TargetSpace> assembler(gridView, *localGFEADOLCStiffness);
//The MixedRiemannianTrustRegionSolver can treat the Displacement and Orientation Space as separate ones
//The RiemannianTrustRegionSolver can only treat the Displacement and Rotation together in a RigidBodyMotion
//Therefore, x and the dirichletDofs are converted to a RigidBodyMotion structure, as well as the Hessian and Gradient that are returned by the assembler
std::vector<TargetSpace> xTargetSpace(compositeBasis.size({0}));
BitSetVector<TargetSpace::TangentVector::dimension> dirichletDofsTargetSpace(compositeBasis.size({0}), false);
for (int i = 0; i < compositeBasis.size({0}); i++) {
for (int j = 0; j < 3; j ++) { // Displacement part
xTargetSpace[i].r[j] = x[_0][i][j];
dirichletDofsTargetSpace[i][j] = deformationDirichletDofs[i][j];
}
xTargetSpace[i].q = x[_1][i]; // Rotation part
for (int j = 3; j < TargetSpace::TangentVector::dimension; j ++)
dirichletDofsTargetSpace[i][j] = orientationDirichletDofs[i][j-3];
}
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
if (parameterSet.get<std::string>("solvertype", "trustRegion") == "trustRegion") {
RiemannianTrustRegionSolver<DeformationFEBasis, TargetSpace> solver;
solver.setup(*grid,
&assembler,
xTargetSpace,
dirichletDofsTargetSpace,
tolerance,
maxSolverSteps,
initialTrustRegionRadius,
multigridIterations,
mgTolerance,
mu, nu1, nu2,
baseIterations,
baseTolerance,
instrumented);
solver.setScaling(parameterSet.get<FieldVector<double,6> >("trustRegionScaling"));
solver.setInitialIterate(xTargetSpace);
solver.solve();
xTargetSpace = solver.getSol();
} else { //parameterSet.get<std::string>("solvertype") == "proximalNewton"
RiemannianProximalNewtonSolver<DeformationFEBasis, TargetSpace> solver;
solver.setup(*grid,
&assembler,
xTargetSpace,
dirichletDofsTargetSpace,
tolerance,
maxSolverSteps,
initialRegularization,
instrumented);
solver.setInitialIterate(xTargetSpace);
solver.solve();
xTargetSpace = solver.getSol();
}
for (int i = 0; i < xTargetSpace.size(); i++) {
x[_0][i] = xTargetSpace[i].r;
x[_1][i] = xTargetSpace[i].q;
}
#endif
}
// Output result of each homotopy step
std::stringstream iAsAscii;
iAsAscii << i+1;
if (dim == dimworld) {
CosseratVTKWriter<GridType>::writeMixed<DeformationFEBasis,OrientationFEBasis>(deformationFEBasis,x[_0],
orientationFEBasis,x[_1],
resultPath + "mixed-cosserat_homotopy_" + iAsAscii.str());
} else {
#if MIXED_SPACE
for (int i = 0; i < displacement.size(); i++) {
for (int j = 0; j < 3; j++) {
displacement[i][j] = x[_0][i][j];
}
displacement[i] -= identity[i];
}
auto displacementFunction = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,3>>(deformationPowerBasis, displacement);
// We need to subsample, because VTK cannot natively display real second-order functions
SubsamplingVTKWriter<GridView> vtkWriter(gridView, Dune::refinementLevels(displacementOrder-1));
vtkWriter.addVertexData(displacementFunction, VTK::FieldInfo("displacement", VTK::FieldInfo::Type::scalar, 3));
vtkWriter.write(resultPath + "cosserat_homotopy_" + std::to_string(i+1));
#else
CosseratVTKWriter<GridType>::write<DeformationFEBasis>(deformationFEBasis, x, resultPath + "cosserat_homotopy_" + std::to_string(i+1));
// //////////////////////////////
// Output result
// //////////////////////////////
#if !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(compositeBasis.size({0}));
for (size_t i=0; i<compositeBasis.size({0}); i++)
for (size_t j=0; j<TargetSpace::TangentVector::dimension; j++)
xEmbedded[i][j] = j < 3 ? x[_0][i][j] : x[_1][i].globalCoordinates()[j-3];
std::ofstream outFile("cosserat-continuum-result-" + std::to_string(numLevels) + ".data", std::ios_base::binary);
MatrixVector::Generic::writeBinary(outFile, xEmbedded);
if (parameterSet.get<bool>("computeAverageNeumannDeflection", false) and parameterSet.hasKey("neumannValues")) {
// 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 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.what() << std::endl;
}