Newer
Older
#ifndef AVERAGE_INTERFACE_HH
#define AVERAGE_INTERFACE_HH
#include <dune/geometry/referenceelements.hh>
#include <dune/geometry/quadraturerules.hh>
#include <dune/common/fmatrix.hh>

Oliver Sander
committed
#include <dune/localfunctions/lagrange/pqkfactory.hh>
#include <dune/istl/preconditioners.hh>
#include dune/matrix-vector/crossproduct.hh>
#include <dune/fufem/dgindexset.hh>

Oliver Sander
committed
#include <dune/fufem/arithmetic.hh>
#include <dune/fufem/surfmassmatrix.hh>
#include <dune/fufem/functions/basisgridfunction.hh>
#include <dune/solvers/common/numproc.hh>
#ifdef HAVE_IPOPT
#include "IpTNLP.hpp"
#include "IpIpoptApplication.hpp"
#else
#error You need IPOpt for this header!
#endif

Oliver Sander
committed
template <class GridView>

Oliver Sander
committed
class PressureAverager : public Ipopt::TNLP
{
typedef double field_type;
typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> > MatrixType;
typedef typename MatrixType::row_type RowType;

Oliver Sander
committed
constexpr static int dim = GridView::dimension;

Oliver Sander
committed
public:
/** \brief Constructor */
PressureAverager(const BoundaryPatch<GridView>* patch,

Oliver Sander
committed
Dune::BlockVector<Dune::FieldVector<double,dim> >* result,
const Dune::FieldVector<double,dim>& resultantForce,
const Dune::FieldVector<double,dim>& resultantTorque,
const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >* massMatrix,
const Dune::BlockVector<Dune::FieldVector<double,1> >* nodalWeights,
const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >* constraintJacobian)
: jacobianCutoff_(1e-12), patch_(patch),

Oliver Sander
committed
massMatrix_(massMatrix), nodalWeights_(nodalWeights),
constraintJacobian_(constraintJacobian), x_(result),

Oliver Sander
committed
resultantForce_(resultantForce), resultantTorque_(resultantTorque)
{
patchArea_ = patch->area();
}

Oliver Sander
committed
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/** default destructor */
virtual ~PressureAverager() {};
/**@name Overloaded from TNLP */
//@{
/** Method to return some info about the nlp */
virtual bool get_nlp_info(Ipopt::Index& n, Ipopt::Index& m, Ipopt::Index& nnz_jac_g,
Ipopt::Index& nnz_h_lag, IndexStyleEnum& index_style);
/** Method to return the bounds for my problem */
virtual bool get_bounds_info(Ipopt::Index n, Ipopt::Number* x_l, Ipopt::Number* x_u,
Ipopt::Index m, Ipopt::Number* g_l, Ipopt::Number* g_u);
/** Method to return the starting point for the algorithm */
virtual bool get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number* x,
bool init_z, Ipopt::Number* z_L, Ipopt::Number* z_U,
Ipopt::Index m, bool init_lambda,
Ipopt::Number* lambda);
/** Method to return the objective value */
virtual bool eval_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Number& obj_value);
/** Method to return the gradient of the objective */
virtual bool eval_grad_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Number* grad_f);
/** Method to return the constraint residuals */
virtual bool eval_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Index m, Ipopt::Number* g);
/** Method to return:
* 1) The structure of the jacobian (if "values" is NULL)
* 2) The values of the jacobian (if "values" is not NULL)
*/
virtual bool eval_jac_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index* iRow, Ipopt::Index *jCol,
Ipopt::Number* values);
/** Method to return:
* 1) The structure of the hessian of the lagrangian (if "values" is NULL)
* 2) The values of the hessian of the lagrangian (if "values" is not NULL)
*/
virtual bool eval_h(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number* lambda,
bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index* iRow,
Ipopt::Index* jCol, Ipopt::Number* values);
//@}
/** @name Solution Methods */
//@{
/** This method is called when the algorithm is complete so the TNLP can store/write the solution */
virtual void finalize_solution(Ipopt::SolverReturn status,
Ipopt::Index n, const Ipopt::Number* x, const Ipopt::Number* z_L, const Ipopt::Number* z_U,
Ipopt::Index m, const Ipopt::Number* g, const Ipopt::Number* lambda,
Ipopt::Number obj_value,
const Ipopt::IpoptData* ip_data,
Ipopt::IpoptCalculatedQuantities* ip_cq);
//@}
// /////////////////////////////////
// Data
// /////////////////////////////////
/** \brief All entries in the constraint Jacobian smaller than the value
here are removed. Apparently this is unnecessary though.

Oliver Sander
committed
*/
const double jacobianCutoff_;
const BoundaryPatch<GridView>* patch_;

Oliver Sander
committed
double patchArea_;
const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >* massMatrix_;
const Dune::BlockVector<Dune::FieldVector<double,1> >* nodalWeights_;
const Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >* constraintJacobian_;
Dune::BlockVector<Dune::FieldVector<double,dim> >* x_;
Dune::FieldVector<double,dim> resultantForce_;
Dune::FieldVector<double,dim> resultantTorque_;
private:
/**@name Methods to block default compiler methods.
*/
//@{
// PressureAverager();
PressureAverager(const PressureAverager&);
PressureAverager& operator=(const PressureAverager&);
//@}
};
// returns the size of the problem

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
get_nlp_info(Ipopt::Index& n, Ipopt::Index& m, Ipopt::Index& nnz_jac_g,
Ipopt::Index& nnz_h_lag, IndexStyleEnum& index_style)
{
// One variable for each vertex on the coupling boundary, and three for the closest constant field
n = patch_->numVertices()*dim + dim;
// prescribed total forces and moments
m = 2*dim;
// number of nonzeroes in the constraint Jacobian
// leave out the very small ones, as they create instabilities
nnz_jac_g = 0;
for (int i=0; i<m; i++) {

Oliver Sander
committed
const RowType& jacobianRow = (*constraintJacobian_)[i];

Oliver Sander
committed
for (typename RowType::ConstIterator cIt = jacobianRow.begin(); cIt!=jacobianRow.end(); ++cIt)
if ( std::abs((*cIt)[0][0]) > jacobianCutoff_ )

Oliver Sander
committed
nnz_jac_g++;

Oliver Sander
committed
}

Oliver Sander
committed
// We only need the lower left corner of the Hessian (since it is symmetric)
if (!massMatrix_)
DUNE_THROW(SolverError, "No mass matrix has been supplied!");
nnz_h_lag = 0;
// use the C style indexing (0-based)
index_style = Ipopt::TNLP::C_STYLE;

Oliver Sander
committed
return true;
}
// returns the variable bounds

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
get_bounds_info(Ipopt::Index n, Ipopt::Number* x_l, Ipopt::Number* x_u,
Ipopt::Index m, Ipopt::Number* g_l, Ipopt::Number* g_u)
{
// here, the n and m we gave IPOPT in get_nlp_info are passed back to us.
// If desired, we could assert to make sure they are what we think they are.
//assert(n == x_->dim());
//assert(m == 0);
// Be on the safe side: unset all variable bounds

Youett, Jonathan
committed
for (int i=0; i<n; i++) {

Oliver Sander
committed
x_l[i] = -std::numeric_limits<double>::max();
x_u[i] = std::numeric_limits<double>::max();
}
for (int i=0; i<dim; i++) {
g_l[i] = g_u[i] = resultantForce_[i];
g_l[i+dim] = g_u[i+dim] = resultantTorque_[i];
}
return true;
}
// returns the initial point for the problem

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
get_starting_point(Ipopt::Index n, bool init_x, Ipopt::Number* x,
bool init_z, Ipopt::Number* z_L, Ipopt::Number* z_U,
Ipopt::Index m, bool init_lambda, Ipopt::Number* lambda)
{
// Here, we assume we only have starting values for x, if you code
// your own NLP, you can provide starting values for the dual variables
// if you wish
assert(init_x == true);
assert(init_z == false);
assert(init_lambda == false);

Oliver Sander
committed
// initialize to the given starting point
for (int i=0; i<n/dim; i++)
for (int j=0; j<dim; j++)
x[i*dim+j] = resultantForce_[j]/patchArea_;

Oliver Sander
committed
return true;
}
// returns the value of the objective function

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
eval_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Number& obj_value)
{
// Init return value
obj_value = 0;
////////////////////////////////////
// Compute x^T*A*x
////////////////////////////////////

Oliver Sander
committed
for (int rowIdx=0; rowIdx<massMatrix_->N(); rowIdx++) {

Oliver Sander
committed
const typename MatrixType::row_type& row = (*massMatrix_)[rowIdx];

Oliver Sander
committed
typename MatrixType::row_type::ConstIterator cIt = row.begin();
typename MatrixType::row_type::ConstIterator cEndIt = row.end();

Oliver Sander
committed
for (; cIt!=cEndIt; ++cIt)
for (int i=0; i<dim; i++)
obj_value += x[dim*rowIdx+i] * x[dim*cIt.index()+i] * (*cIt)[0][0];
}

Oliver Sander
committed
for (int i=0; i<nodalWeights_->size(); i++)
for (int j=0; j<dim; j++)
obj_value -= 2 * x[n-dim + j] * x[i*dim+j] * (*nodalWeights_)[i];

Oliver Sander
committed
// += c^2 * \int 1 ds
for (int i=0; i<dim; i++)
obj_value += patchArea_ * (x[n-dim + i] * x[n-dim + i]);
return true;
}
// return the gradient of the objective function grad_{x} f(x)

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
eval_grad_f(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Number* grad_f)
{
//std::cout << "### eval_grad_f ###" << std::endl;
// \nabla J = A(x,.) - b(x)
for (int i=0; i<n; i++)
grad_f[i] = 0;
for (int i=0; i<massMatrix_->N(); i++) {
const typename MatrixType::row_type& row = (*massMatrix_)[i];
typename MatrixType::row_type::ConstIterator cIt = row.begin();
typename MatrixType::row_type::ConstIterator cEndIt = row.end();

Oliver Sander
committed
for (int j=0; j<dim; j++)
grad_f[i*dim+j] += 2 * (*cIt)[0][0] * x[cIt.index()*dim+j];
for (int j=0; j<dim; j++)
grad_f[i*dim+j] -= 2 * x[n-dim+j] * (*nodalWeights_)[i];

Oliver Sander
committed
}
for (int i=0; i<dim; i++) {

Oliver Sander
committed
grad_f[n-dim+i] -= 2* (*nodalWeights_)[j]*x[j*dim+i];
grad_f[n-dim+i] += 2*x[n-dim+i]*patchArea_;

Oliver Sander
committed
}
// for (int i=0; i<n; i++) {
// std::cout << "x = " << x[i] << std::endl;
// std::cout << "grad = " << grad_f[i] << std::endl;
// }

Oliver Sander
committed
return true;
}
// return the value of the constraints: g(x)

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
eval_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x, Ipopt::Index m, Ipopt::Number* g)
{
for (int i=0; i<m; i++) {
// init
g[i] = 0;
const RowType& jacobianRow = (*constraintJacobian_)[i];
for (typename RowType::ConstIterator cIt = jacobianRow.begin(); cIt!=jacobianRow.end(); ++cIt)
if ( std::abs((*cIt)[0][0]) > jacobianCutoff_ ) {
//printf("adding %g times %g\n", (*cIt)[0][0], x[cIt.index()]);

Oliver Sander
committed
g[i] += (*cIt)[0][0] * x[cIt.index()];

Oliver Sander
committed
}
// for (int i=0; i<m; i++)
// std::cout << "g[" << i << "]: " << g[i] << std::endl;

Oliver Sander
committed
return true;
}
// return the structure or values of the jacobian

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
eval_jac_g(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
Ipopt::Index m, Ipopt::Index nele_jac, Ipopt::Index* iRow, Ipopt::Index *jCol,
Ipopt::Number* values)
{
int idx = 0;
if (values==NULL) {
for (int i=0; i<m; i++) {

Oliver Sander
committed
const RowType& jacobianRow = (*constraintJacobian_)[i];

Oliver Sander
committed
for (typename RowType::ConstIterator cIt = jacobianRow.begin(); cIt!=jacobianRow.end(); ++cIt) {
if ( std::abs((*cIt)[0][0]) > jacobianCutoff_ ) {

Oliver Sander
committed
iRow[idx] = i;
jCol[idx] = cIt.index();
idx++;
}
}

Oliver Sander
committed
}
} else {
for (int i=0; i<m; i++) {

Oliver Sander
committed
const RowType& jacobianRow = (*constraintJacobian_)[i];

Oliver Sander
committed
for (typename RowType::ConstIterator cIt = jacobianRow.begin(); cIt!=jacobianRow.end(); ++cIt)
if ( std::abs((*cIt)[0][0]) > jacobianCutoff_ )

Oliver Sander
committed
values[idx++] = (*cIt)[0][0];

Oliver Sander
committed
}
}
return true;
}
//return the structure or values of the hessian

Oliver Sander
committed
template <class GridView>
bool PressureAverager<GridView>::

Oliver Sander
committed
eval_h(Ipopt::Index n, const Ipopt::Number* x, bool new_x,
Ipopt::Number obj_factor, Ipopt::Index m, const Ipopt::Number* lambda,
bool new_lambda, Ipopt::Index nele_hess, Ipopt::Index* iRow,
Ipopt::Index* jCol, Ipopt::Number* values)
{
// We are using a quasi-Hessian approximation
return false;
}

Oliver Sander
committed
template <class GridView>
void PressureAverager<GridView>::

Oliver Sander
committed
finalize_solution(Ipopt::SolverReturn status,
Ipopt::Index n, const Ipopt::Number* x, const Ipopt::Number* z_L, const Ipopt::Number* z_U,
Ipopt::Index m, const Ipopt::Number* g, const Ipopt::Number* lambda,
Ipopt::Number obj_value,
const Ipopt::IpoptData* ip_data,
Ipopt::IpoptCalculatedQuantities* ip_cq)
{
x_->resize(patch_->numVertices());

Oliver Sander
committed
for (int i=0; i<x_->size(); i++)
for (int j=0; j<dim; j++)
(*x_)[i][j] = x[i*dim+j];
}
template <class GridView>
void weakToStrongBoundaryStress(const BoundaryPatch<GridView>& boundary,
const Dune::BlockVector<Dune::FieldVector<double, GridView::dimension> >& weakBoundaryStress,
Dune::BlockVector<Dune::FieldVector<double, GridView::dimension> >& strongBoundaryStress)
{
static const int dim = GridView::dimension;
typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,dim,dim> > MatrixType;
typedef Dune::BlockVector<Dune::FieldVector<double,dim> > VectorType;
// turn residual (== weak form of the Neumann forces) to the strong form
MatrixType surfaceMassMatrix;
assembleSurfaceMassMatrix(boundary, surfaceMassMatrix);
std::vector<int> globalToLocal;
boundary.makeGlobalToLocal(globalToLocal);
VectorType localWeakBoundaryStress(surfaceMassMatrix.N());
assert(globalToLocal.size()==weakBoundaryStress.size());
for (int i=0; i<globalToLocal.size(); i++)
if (globalToLocal[i] >= 0)
localWeakBoundaryStress[globalToLocal[i]] = weakBoundaryStress[i];
VectorType localStrongBoundaryStress(surfaceMassMatrix.N());
localStrongBoundaryStress = 0;
// solve with a cg solver
Dune::MatrixAdapter<MatrixType,VectorType,VectorType> op(surfaceMassMatrix);
Dune::SeqILU0<MatrixType,VectorType,VectorType> ilu0(surfaceMassMatrix,1.0);
Dune::CGSolver<VectorType> cg(op,ilu0,1E-4,100,0);
Dune::InverseOperatorResult statistics;
cg.apply(localStrongBoundaryStress, localWeakBoundaryStress, statistics);
VectorType neumannForces(weakBoundaryStress.size());
neumannForces = 0;
for (int i=0; i<globalToLocal.size(); i++)
if (globalToLocal[i] >= 0)
strongBoundaryStress[i] = localStrongBoundaryStress[globalToLocal[i]];
}
/** \param center Compute total torque around this point
*/
template <class GridView>
void computeTotalForceAndTorque(const BoundaryPatch<GridView>& interface,

Oliver Sander
committed
const Dune::BlockVector<Dune::FieldVector<double, GridView::dimension> >& boundaryStress,
const Dune::FieldVector<double,3>& center,

Oliver Sander
committed
Dune::FieldVector<double,3>& totalForce, Dune::FieldVector<double,3>& totalTorque)
{
const int dim = GridView::dimension;

Oliver Sander
committed
// ///////////////////////////////////////////
// Initialize output configuration
// ///////////////////////////////////////////
totalForce = 0;
totalTorque = 0;

Oliver Sander
committed
////////////////////////////////////////////////////////////////
// Interpret the Neumann value coefficients as a P1 function
////////////////////////////////////////////////////////////////
typedef P1NodalBasis<GridView,double> P1Basis;
P1Basis p1Basis(interface.gridView());
BasisGridFunction<P1Basis, Dune::BlockVector<Dune::FieldVector<double, GridView::dimension> > > neumannFunction(p1Basis, boundaryStress);

Oliver Sander
committed
// ///////////////////////////////////////////
// Loop and integrate over the interface
// ///////////////////////////////////////////
typename BoundaryPatch<GridView>::iterator it = interface.begin();
typename BoundaryPatch<GridView>::iterator endIt = interface.end();

Oliver Sander
committed
for (; it!=endIt; ++it) {
const typename BoundaryPatch<GridView>::iterator::Intersection::Geometry& segmentGeometry = it->geometry();

Oliver Sander
committed
// Get quadrature rule
const Dune::QuadratureRule<double, dim-1>& quad = Dune::QuadratureRules<double, dim-1>::rule(segmentGeometry.type(), dim-1);

Oliver Sander
committed
/* Loop over all integration points */
for (size_t ip=0; ip<quad.size(); ip++) {

Oliver Sander
committed
// Local position of the quadrature point
const Dune::FieldVector<double,dim> quadPos = it->geometryInInside().global(quad[ip].position());
const Dune::FieldVector<double,dim> worldPos = it->geometry().global(quad[ip].position());

Oliver Sander
committed
const double integrationElement = segmentGeometry.integrationElement(quad[ip].position());

Oliver Sander
committed
Dune::FieldVector<double,dim> value;
neumannFunction.evaluateLocal(*it->inside(), quadPos, value);

Oliver Sander
committed
totalForce.axpy(quad[ip].weight() * integrationElement, value);
totalTorque.axpy(quad[ip].weight() * integrationElement, MatrixVector::crossProduct(worldPos-center,value));

Oliver Sander
committed
}

Oliver Sander
committed

Oliver Sander
committed
// Given a resultant force and torque (from a rod problem), this method computes the corresponding
// Neumann data for a 3d elasticity problem.

Oliver Sander
committed
template <class GridView>
void computeAveragePressure(const typename RigidBodyMotion<double,GridView::dimension>::TangentVector& resultantForceTorque,
const BoundaryPatch<GridView>& interface,
const Dune::FieldVector<double,GridView::dimension>& centerOfTorque,

Oliver Sander
committed
Dune::BlockVector<Dune::FieldVector<double, GridView::dimension> >& pressure)

Oliver Sander
committed
{

Oliver Sander
committed
const GridView& gridView = interface.gridView();
const typename GridView::IndexSet& indexSet = gridView.indexSet();
const int dim = GridView::dimension;

Oliver Sander
committed
typedef double field_type;

Oliver Sander
committed
Dune::PQkLocalFiniteElementCache<double,double, dim, 1> finiteElementCache;

Oliver Sander
committed

Oliver Sander
committed
// Create the matrix of constraints
Dune::BCRSMatrix<Dune::FieldMatrix<field_type,1,1> > constraints(2*dim, dim*interface.numVertices(),
Dune::BCRSMatrix<Dune::FieldMatrix<double,1,1> >::random);

Oliver Sander
committed
for (int i=0; i<dim; i++) {
constraints.setrowsize(i, interface.numVertices());
constraints.setrowsize(i+dim, dim*interface.numVertices());

Oliver Sander
committed
}

Oliver Sander
committed
for (int i=0; i<dim; i++)
for (int j=0; j<interface.numVertices(); j++)

Oliver Sander
committed
for (int i=0; i<dim; i++)
for (int j=0; j<dim*interface.numVertices(); j++)

Oliver Sander
committed

Oliver Sander
committed

Oliver Sander
committed
// Create the surface mass matrix
Dune::BCRSMatrix<Dune::FieldMatrix<field_type,1,1> > massMatrix;

Oliver Sander
committed
assembleSurfaceMassMatrix<GridView, 1>(interface, massMatrix);

Oliver Sander
committed
// Make global-to-local array
std::vector<int> globalToLocal;
interface.makeGlobalToLocal(globalToLocal);
// Make array of nodal weights
Dune::BlockVector<Dune::FieldVector<double,1> > nodalWeights(interface.numVertices());
nodalWeights = 0;
typename BoundaryPatch<GridView>::iterator it = interface.begin();
typename BoundaryPatch<GridView>::iterator endIt = interface.end();

Oliver Sander
committed

Oliver Sander
committed

Oliver Sander
committed
// Get shape functions
const typename Dune::PQkLocalFiniteElementCache<double,double, dim, 1>::FiniteElementType&

Oliver Sander
committed
localFiniteElement = finiteElementCache.get(it->inside()->type());

Oliver Sander
committed
const Dune::ReferenceElement<double,dim>& refElement = Dune::ReferenceElements<double, dim>::general(it->inside()->type());

Oliver Sander
committed
// four rows because a face may have no more than four vertices
Dune::FieldVector<double,4> mu(0);
Dune::FieldVector<double,3> mu_tilde[4][3];

Oliver Sander
committed
for (int i=0; i<4; i++)
for (int j=0; j<3; j++)
mu_tilde[i][j] = 0;
for (int i=0; i<it->geometry().corners(); i++) {
const Dune::QuadratureRule<double, dim-1>& quad

Oliver Sander
committed
= Dune::QuadratureRules<double, dim-1>::rule(it->type(), dim-1);

Oliver Sander
committed
for (size_t qp=0; qp<quad.size(); qp++) {

Oliver Sander
committed
// Local position of the quadrature point

Oliver Sander
committed
const Dune::FieldVector<double,dim>& quadPos = it->geometryInInside().global(quad[qp].position());

Oliver Sander
committed
const double integrationElement = it->geometry().integrationElement(quad[qp].position());

Oliver Sander
committed
std::vector<Dune::FieldVector<double,1> > shapeFunctionValues;
localFiniteElement.localBasis().evaluateFunction(quadPos, shapeFunctionValues);

Oliver Sander
committed
// \mu_i = \int_t \varphi_i \ds

Oliver Sander
committed
int indexInFace = refElement.subEntity(it->indexInInside(), 1, i, dim);
mu[i] += quad[qp].weight() * integrationElement * shapeFunctionValues[indexInFace];
// \tilde{\mu}_i^j = \int_t (x - x_0) \times \varphi_i \ds

Oliver Sander
committed
Dune::FieldVector<double,dim> worldPos = it->geometry().global(quad[qp].position());

Oliver Sander
committed
for (int j=0; j<dim; j++) {
// Vector-valued basis function
Dune::FieldVector<double,dim> phi_i(0);

Oliver Sander
committed
phi_i[j] = shapeFunctionValues[indexInFace];

Oliver Sander
committed
mu_tilde[i][j].axpy(quad[qp].weight() * integrationElement,

Oliver Sander
committed
Arithmetic::crossProduct(Dune::FieldVector<double,dim>(worldPos-centerOfTorque), phi_i));

Oliver Sander
committed
}

Oliver Sander
committed
}

Oliver Sander
committed
}
// Set up matrix

Oliver Sander
committed
for (int i=0; i<refElement.size(it->indexInInside(),1,dim); i++) {
int faceIdxi = refElement.subEntity(it->indexInInside(), 1, i, dim);
int subIndex = globalToLocal[indexSet.subIndex(*it->inside(), faceIdxi, dim)];

Oliver Sander
committed
nodalWeights[subIndex] += mu[i];
for (int j=0; j<dim; j++)
constraints[j][subIndex*dim+j] += mu[i];

Oliver Sander
committed
for (int j=0; j<3; j++)
for (int k=0; k<3; k++)
constraints[dim+k][dim*subIndex+j] += mu_tilde[i][j][k];

Oliver Sander
committed
}
}
//printmatrix(std::cout, constraints, "jacobian", "--");

Oliver Sander
committed
//printmatrix(std::cout, massMatrix, "mass", "--");
// /////////////////////////////////////////////////////////////////////////////////////
// Set up and start the interior-point solver
// /////////////////////////////////////////////////////////////////////////////////////
Dune::FieldVector<double,dim> resultantForce, resultantTorque;
for (int i=0; i<dim; i++) {
resultantForce[i] = resultantForceTorque[i];
resultantTorque[i] = resultantForceTorque[dim+i];
}

Oliver Sander
committed
// Create a new instance of IpoptApplication
Ipopt::SmartPtr<Ipopt::IpoptApplication> app = new Ipopt::IpoptApplication();

Oliver Sander
committed
// Change some options

Oliver Sander
committed
app->Options()->SetNumericValue("tol", 1e-8);
app->Options()->SetIntegerValue("max_iter", 1000);

Oliver Sander
committed
app->Options()->SetStringValue("mu_strategy", "adaptive");
app->Options()->SetStringValue("output_file", "ipopt.out");
app->Options()->SetStringValue("hessian_approximation", "limited-memory");
app->Options()->SetStringValue("jac_c_constant", "yes");

Oliver Sander
committed
app->Options()->SetIntegerValue("print_level", 0);

Oliver Sander
committed
// Initialize the IpoptApplication and process the options

Oliver Sander
committed
Ipopt::ApplicationReturnStatus status;
status = app->Initialize();

Oliver Sander
committed
if (status != Ipopt::Solve_Succeeded)

Oliver Sander
committed
DUNE_THROW(SolverError, "Error during IPOpt initialization!");

Oliver Sander
committed
// Ask Ipopt to solve the problem
Dune::BlockVector<Dune::FieldVector<double,dim> > localPressure;

Oliver Sander
committed
Ipopt::SmartPtr<Ipopt::TNLP> defectSolverSmart = new PressureAverager<GridView>(&interface,

Oliver Sander
committed
&localPressure,
resultantForce,
resultantTorque,
&massMatrix,
&nodalWeights,

Oliver Sander
committed
status = app->OptimizeTNLP(defectSolverSmart);

Oliver Sander
committed
if (status != Ipopt::Solve_Succeeded
&& status != Ipopt::Solved_To_Acceptable_Level) {
//DUNE_THROW(SolverError, "Solving the defect problem failed!");
std::cout << "IPOpt returned error code " << status << "!" << std::endl;
}

Oliver Sander
committed
// //////////////////////////////////////////////////////////////////////////////
// Get result
// //////////////////////////////////////////////////////////////////////////////
// set up output array
pressure.resize(indexSet.size(dim));
pressure = 0;
for (size_t i=0; i<globalToLocal.size(); i++)
if (globalToLocal[i]>=0)
pressure[i] = localPressure[globalToLocal[i]];
// /////////////////////////////////////////////////////////////////////////////////////
// Compute the overall force and torque to see whether the preceding code is correct
// /////////////////////////////////////////////////////////////////////////////////////
Dune::FieldVector<double,3> outputForce(0), outputTorque(0);

Oliver Sander
committed
computeTotalForceAndTorque(interface, pressure, centerOfTorque, outputForce, outputTorque);

Oliver Sander
committed
outputForce -= resultantForce;
outputTorque -= resultantTorque;
assert( outputForce.infinity_norm() < 1e-6 );
assert( outputTorque.infinity_norm() < 1e-6 );
// std::cout << "Output force: " << outputForce << std::endl;
// std::cout << "Output torque: " << outputTorque << " " << resultantTorque[0]/outputTorque[0] << std::endl;
}

Oliver Sander
committed
template <class GridView>
void computeAverageInterface(const BoundaryPatch<GridView>& interface,

Oliver Sander
committed
const Dune::BlockVector<Dune::FieldVector<double,GridView::dimension> > deformation,
{
using namespace Dune;

Oliver Sander
committed
typedef typename GridView::template Codim<0>::Entity EntityType;

Jonathan Youett
committed
typedef typename GridView::IntersectionIterator NeighborIterator;

Oliver Sander
committed
const GridView& gridView = interface.gridView();
const typename GridView::IndexSet& indexSet = gridView.indexSet();
const int dim = GridView::dimension;

Oliver Sander
committed
Dune::PQkLocalFiniteElementCache<double,double, dim, 1> finiteElementCache;
// ///////////////////////////////////////////
// Initialize output configuration
// ///////////////////////////////////////////
average.r = 0;
double interfaceArea = 0;
FieldMatrix<double,dim,dim> deformationGradient(0);
// ///////////////////////////////////////////
// Loop and integrate over the interface
// ///////////////////////////////////////////
typename BoundaryPatch<GridView>::iterator it = interface.begin();
typename BoundaryPatch<GridView>::iterator endIt = interface.end();

Oliver Sander
committed
const typename NeighborIterator::Intersection::Geometry& segmentGeometry = it->geometry();
// Get quadrature rule
const QuadratureRule<double, dim-1>& quad = QuadratureRules<double, dim-1>::rule(segmentGeometry.type(), dim-1);
// Get set of shape functions on this segment
const typename Dune::PQkLocalFiniteElementCache<double,double, dim, 1>::FiniteElementType&

Oliver Sander
committed
localFiniteElement = finiteElementCache.get(it->inside()->type());
/* Loop over all integration points */
for (int ip=0; ip<quad.size(); ip++) {
// Local position of the quadrature point
const FieldVector<double,dim> quadPos = it->geometryInInside().global(quad[ip].position());
const double integrationElement = segmentGeometry.integrationElement(quad[ip].position());

Oliver Sander
committed
std::vector<Dune::FieldVector<double,1> > values;
localFiniteElement.localBasis().evaluateFunction(quadPos,values);
// Evaluate base functions
FieldVector<double,dim> posAtQuadPoint(0);
for(int i=0; i<it->inside()->geometry().corners(); i++) {
int idx = indexSet.subIndex(*it->inside(), i, dim);

Oliver Sander
committed
posAtQuadPoint.axpy(values[i], deformation[idx]);
}
const FieldMatrix<double,dim,dim>& inv = it->inside()->geometry().jacobianInverseTransposed(quadPos);
/**********************************************/
/* compute gradients of the shape functions */
/**********************************************/

Oliver Sander
committed
std::vector<FieldMatrix<double, 1, dim> > shapeGrads;
localFiniteElement.localBasis().evaluateJacobian(quadPos,shapeGrads);
for (int dof=0; dof<it->inside()->geometry().corners(); dof++) {

Oliver Sander
committed
FieldVector<double,dim> tmp = shapeGrads[dof][0];

Oliver Sander
committed
shapeGrads[dof] = 0;

Oliver Sander
committed
inv.umv(tmp, shapeGrads[dof][0]);
}
/****************************************************/
// The deformation gradient of the deformation
// in formulas: F(i,j) = $\partial \phi_i / \partial x_j$
// or F(i,j) = Id + $\partial u_i / \partial x_j$
/****************************************************/
FieldMatrix<double, dim, dim> F;
for (int i=0; i<dim; i++) {
for (int j=0; j<dim; j++) {
F[i][j] = (i==j) ? 1 : 0;
for (int k=0; k<it->inside()->geometry().corners(); k++)

Oliver Sander
committed
F[i][j] += deformation[indexSet.subIndex(*it->inside(), k, dim)][i]*shapeGrads[k][0][j];
}

Oliver Sander
committed
// Sum up interface area
interfaceArea += quad[ip].weight() * integrationElement;

Oliver Sander
committed
// Sum up average displacement
average.r.axpy(quad[ip].weight() * integrationElement, posAtQuadPoint);

Oliver Sander
committed
// Sum up average deformation gradient
for (int i=0; i<dim; i++)
for (int j=0; j<dim; j++)
deformationGradient[i][j] += F[i][j] * quad[ip].weight() * integrationElement;
}
}
// average deformation of the interface is the integral over its
// deformation divided by its area
average.r /= interfaceArea;
// average deformation is the integral over the deformation gradient
// divided by its area
deformationGradient /= interfaceArea;
//std::cout << "deformationGradient: " << std::endl << deformationGradient << std::endl;
// Get the rotational part of the deformation gradient by performing a
// polar composition.
FieldVector<double,dim> W;
FieldMatrix<double,dim,dim> V, VT, U;
// returns a decomposition U W VT, where U is returned in the first argument
svdcmp<double,dim,dim>(deformationGradient, W, V);
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
VT[i][j] = V[j][i];
// deformationGradient now contains the orthogonal part of the polar decomposition
assert( std::abs(1-deformationGradient.determinant()) < 1e-3);
}
/** \brief Set a Dirichlet value that corresponds to a given rigid body motion
*/
template <class GridView>
void setRotation(const BoundaryPatch<GridView>& dirichletBoundary,
Dune::BlockVector<Dune::FieldVector<double,GridView::dimension> >& deformation,
const RigidBodyMotion<double,3>& referenceInterface,
const RigidBodyMotion<double,3>& lambda)
{
const typename GridView::IndexSet& indexSet = dirichletBoundary.gridView().indexSet();
const int dim = GridView::dimension;
const int dimworld = GridView::dimensionworld;
// Get the relative rotation, first as a quaternion...

Youett, Jonathan
committed
relativeRotation = Rotation<double,3>(referenceInterface.q.inverse());
relativeRotation = lambda.q.mult(relativeRotation);
// ... then as a matrix
Dune::FieldMatrix<double,3,3> rotation;
relativeRotation.matrix(rotation);
// ///////////////////////////////////////////
// Loop over all vertices
// ///////////////////////////////////////////
typename BoundaryPatch<GridView>::iterator it = dirichletBoundary.begin();
typename BoundaryPatch<GridView>::iterator endIt = dirichletBoundary.end();
for (; it!=endIt; ++it) {
int indexInInside = it->indexInInside();
int nCorners = Dune::ReferenceElements<double,dim>::general(it->inside()->type()).size(indexInInside, 1, dim);
for (int i=0; i<nCorners; i++) {
int cornerIdx = Dune::ReferenceElements<double,dim>::general(it->inside()->type()).subEntity(it->indexInInside(), 1, i, dim);
int globalIdx = indexSet.subIndex(*it->inside(), cornerIdx, dim);
const Dune::FieldVector<double,dimworld> pos = it->inside()->geometry().corner(cornerIdx);
// Action of the rigid body motion
Dune::FieldVector<double,dimworld> rpos;
rotation.mv(pos-referenceInterface.r, rpos);
rpos += lambda.r;
// We compute _displacements_, not positions
rpos -= pos;
deformation[globalIdx] = rpos;