Newer
Older
#include <iostream>
#include <fstream>
#include <config.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>
#include <dune/fufem/utilities/adolcnamespaceinjections.hh>
#include <dune/common/parametertree.hh>
#include <dune/common/parametertreeparser.hh>
#include <dune/common/version.hh>
#if DUNE_VERSION_GTE(DUNE_ELASTICITY, 2, 11)
#include <dune/elasticity/densities/stvenantkirchhoffdensity.hh>
#else
#include <dune/elasticity/materials/stvenantkirchhoffdensity.hh>
#include <dune/functions/functionspacebases/interpolate.hh>
#include <dune/functions/functionspacebases/lagrangebasis.hh>
#include <dune/functions/functionspacebases/powerbasis.hh>
#include <dune/functions/gridfunctions/discreteglobalbasisfunction.hh>
#include <dune/grid/uggrid.hh>
#include <dune/grid/utility/structuredgridfactory.hh>
#include <dune/gfe/filereader.hh>
#include <dune/gfe/assemblers/surfacecosseratstressassembler.hh>
#include <dune/gfe/spaces/rotation.hh>
#include <dune/matrix-vector/transpose.hh>
// grid dimension
#ifndef WORLD_DIM
# define WORLD_DIM 3
#endif
const int dim = WORLD_DIM;
const int displacementOrder = 2;
const int rotationOrder = 2;
using namespace Dune;
using ValueType = adouble;
// Surface Shell Boundary
std::function<bool(FieldVector<double,dim>)> isSurfaceShellBoundary = [](FieldVector<double,dim> coordinate) {
return coordinate[2] > 199.99 and coordinate[0] > 49.99 and coordinate[0] < 150.01;
};
static bool sameEntries(FieldVector<double,3> a,FieldVector<double,3> b) {
b[1] *= -1;
b -= a;
//If a.two_norm > 0, so if there is a displacement at this points: Scale the difference with the length of the vectors
return a.two_norm() > 0 ? b.two_norm()/a.two_norm() < 0.05 : b.two_norm() < 0.05;
}
static bool sameEntries(FieldVector<double,4> a,FieldVector<double,4> b) {
Rotation<double,dim> rotationA(a);
Rotation<double,dim> rotationB(b);
rotationA.mult(rotationB);
Rotation<double,dim> identity;
auto distance = Rotation<double,dim>::distance(rotationA, identity);
return distance < 0.01;
}
template <int d>
static bool symmetryTest(std::unordered_map<std::string, FieldVector<double,d> > map, double axis) {
bool isSame = true;
std::string entry;
for (auto it = map.begin(); it != map.end(); it++) {
auto stringKey = it->first;
std::stringstream entries(stringKey);
FieldVector<double,dim> coordinate(0);
int j = 0;
while(entries >> entry)
coordinate[j++] = std::stod(entry);
if (coordinate[1] < axis) {
coordinate[1] -= 2*axis;
coordinate[1] *= -1;
std::stringstream stream;
stream << coordinate; //modified coordinate
if (map.count(stream.str()) > 0 && isSurfaceShellBoundary(coordinate)) {
bool thisIsSame = sameEntries(it->second, map.at(stream.str()));
isSame = isSame && thisIsSame;
}
}
}
return isSame;
}
int main (int argc, char *argv[])
{
MPIHelper::instance(argc, argv);
/////////////////////////////////////////////////////////////
// CREATE THE GRID
/////////////////////////////////////////////////////////////
typedef UGGrid<dim> GridType;
std::shared_ptr<GridType> grid = StructuredGridFactory<GridType>::createCubeGrid({0,0,0}, {200, 60, 200}, {10,3,5});
grid->setRefinementType(GridType::RefinementType::COPY);
int numLevels = 4;
for (auto&& e : elements(grid->leafGridView())) {
bool isSurfaceShell = false;
for (int i = 0; i < e.geometry().corners(); i++) {
isSurfaceShell = isSurfaceShell || isSurfaceShellBoundary(e.geometry().corner(i));
}
grid->mark(isSurfaceShell ? 1 : 0,e);
}
grid->adapt();
numLevels--;
}
typedef GridType::LeafGridView GridView;
GridView gridView = grid->leafGridView();
/////////////////////////////////////////////////////////////
// SURFACE SHELL BOUNDARY
/////////////////////////////////////////////////////////////
const GridView::IndexSet& indexSet = gridView.indexSet();
BitSetVector<1> surfaceShellVertices(gridView.size(dim), false);
for (auto&& v : vertices(gridView))
{
bool isSurfaceShell = isSurfaceShellBoundary(v.geometry().corner(0));
surfaceShellVertices[indexSet.index(v)] = isSurfaceShell;
}
BoundaryPatch<GridView> surfaceShellBoundary(gridView, surfaceShellVertices);
std::function<Dune::FieldVector<double,2>(Dune::FieldVector<double,dim>)> fLame = [](Dune::FieldVector<double,dim> x){
Dune::FieldVector<double,2> lameConstants {1.24E+07,2.52E+07}; //stiffness = 33
return lameConstants;
};
/////////////////////////////////////////////////////////////
// FUNCTION SPACE
/////////////////////////////////////////////////////////////
using namespace Functions::BasisFactory;
auto basisOrderD = makeBasis(
gridView,
power<dim>(
lagrange<displacementOrder>()
));
auto basisOrderR = makeBasis(
gridView,
power<dim>(
lagrange<rotationOrder>()
));
/////////////////////////////////////////////////////////////
// READ IN TEST DATA
/////////////////////////////////////////////////////////////
auto deformationMap = Dune::GFE::transformFileToMap<dim>("./stressPlotData/stressPlotTestDeformation");
auto initialDeformationMap = Dune::GFE::transformFileToMap<dim>("./stressPlotData/stressPlotTestInitialDeformation");
const auto dimRotation = Rotation<double,dim>::embeddedDim;
auto rotationMap = Dune::GFE::transformFileToMap<dimRotation>("./stressPlotData/stressPlotTestRotation");
bool deformationIsSymmetric = symmetryTest<dim>(deformationMap, 30);
bool rotationIsSymmetric = symmetryTest<dimRotation>(rotationMap, 30);
if (!deformationIsSymmetric) {
std::cerr << "The stressAssemblerTest checking for symmetry only works with a symmetric deformation input file! Please check the file for symmetry!" << std::endl;
return 1;
}
if (!rotationIsSymmetric) {
std::cout << "The rotation is not symmetric, but that is still ok!" << std::endl;
}
using DisplacementVector = std::vector<FieldVector<double,dim> >;
DisplacementVector x;
x.resize(basisOrderD.size());
DisplacementVector xInitial;
xInitial.resize(basisOrderD.size());
DisplacementVector displacement;
displacement.resize(basisOrderD.size());
Functions::interpolate(basisOrderD, x, [](FieldVector<double,dim> x){
return x;
});
Functions::interpolate(basisOrderD, xInitial, [](FieldVector<double,dim> x){
return x;
});
for (std::size_t i = 0; i < basisOrderD.size(); i++) {
std::stringstream stream;
stream << x[i];
//Look up the displacement for this vertex in the deformationMap
displacement[i] = deformationMap.at(stream.str());
x[i] += deformationMap.at(stream.str());
xInitial[i] += initialDeformationMap.at(stream.str());
}
using RotationVector = std::vector<Rotation<double,dim> >;
RotationVector rot;
rot.resize(basisOrderR.size());
DisplacementVector xOrderR;
xOrderR.resize(basisOrderR.size());
Functions::interpolate(basisOrderR, xOrderR, [](FieldVector<double,dim> x){
return x;
});
for (std::size_t i = 0; i < basisOrderR.size(); i++) {
std::stringstream stream;
stream << xOrderR[i];
Rotation<double,dim> rotation(rotationMap.at(stream.str()));
FieldMatrix<double,dim,dim> rotationMatrix(0);
rotation.matrix(rotationMatrix);
rot[i].set(rotationMatrix);
}
MultipleCodimMultipleGeomTypeMapper<GridView> elementMapper(basisOrderD.gridView(),mcmgElementLayout());
std::vector<int> indicesOfMirroredElements(0);
indicesOfMirroredElements.resize(elementMapper.size());
std::unordered_map<std::string, int> elementCenterMirrorMap;
static constexpr auto partitionType = Partitions::interiorBorder;
for (const auto& element : elements(basisOrderD.gridView(), partitionType)) {
std::stringstream stream;
stream << element.geometry().center();
elementCenterMirrorMap.insert({stream.str(), elementMapper.index(element)});
}
/////////////////////////////////////////////////////////////
// STRESS ASSEMBLER
/////////////////////////////////////////////////////////////
auto quadOrder = 4;
auto stressAssembler = GFE::SurfaceCosseratStressAssembler<decltype(basisOrderD),decltype(basisOrderR), FieldVector<double,dim>, Rotation<double,dim> >
(basisOrderD, basisOrderR);
std::shared_ptr<Elasticity::LocalDensity<dim,ValueType> > elasticDensity;
ParameterTree materialParameters;
materialParameters["mu"] = "2.7191e+4";
materialParameters["lambda"] = "4.4364e+4";
elasticDensity = std::make_shared<Elasticity::StVenantKirchhoffDensity<dim,ValueType> >(materialParameters);
std::vector<FieldMatrix<double,dim,dim> > stressSubstrate1stPiolaKirchhoffTensor;
std::vector<FieldMatrix<double,dim,dim> > stressSubstrateCauchyTensor;
stressAssembler.assembleSubstrateStress<Elasticity::LocalDensity<dim,ValueType> >(x, elasticDensity.get(), quadOrder, stressSubstrate1stPiolaKirchhoffTensor, stressSubstrateCauchyTensor);
std::vector<FieldMatrix<double,dim,dim> > stressShellBiotTensor;
stressAssembler.assembleShellStress(rot, x, xInitial, fLame,/*mu_c*/ 0, surfaceShellBoundary, quadOrder, stressShellBiotTensor);
//Now modify ONE value in the rotation function
int i = 39787;
FieldMatrix<double,dim,dim> rotationMatrix(0);
FieldMatrix<double,dim,dim> transposed(0);
rot[i].matrix(rotationMatrix);
Dune::MatrixVector::transpose(transposed, rotationMatrix);
rot[i].set(transposed);
std::vector<FieldMatrix<double,dim,dim> > stressShellBiotTensorNotSymmetric;
stressAssembler.assembleShellStress(rot, x, xInitial, fLame,/*mu_c*/ 0, surfaceShellBoundary, quadOrder, stressShellBiotTensorNotSymmetric);
// ... and ONE in the displacement function
x[i] *= 2;
std::vector<FieldMatrix<double,dim,dim> > stressSubstrate1stPiolaKirchhoffTensorNotSymmetric;
std::vector<FieldMatrix<double,dim,dim> > stressSubstrateCauchyTensorNotSymmetric;
stressAssembler.assembleSubstrateStress<Elasticity::LocalDensity<dim,ValueType> >(x, elasticDensity.get(), quadOrder, stressSubstrate1stPiolaKirchhoffTensorNotSymmetric, stressSubstrateCauchyTensorNotSymmetric);
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
// ... and make sure that the stress is not symmetric anymore!
bool substrateModifiedIsNotSymmetric = false;
bool shellModifiedIsNotSymmetric = false;
auto axis = 30; //test for symmetry for the plane at y=30
for (const auto& element : elements(basisOrderD.gridView(), partitionType)) {
auto elementCenter = element.geometry().center();
elementCenter[1] -= 2*axis;
elementCenter[1] *= -1;
int thisIndex = elementMapper.index(element);
std::stringstream stream;
stream << elementCenter;
int mirroredIndex = elementCenterMirrorMap.at(stream.str());
auto substrate = stressSubstrate1stPiolaKirchhoffTensor[thisIndex];
auto mirroredSubstrate = stressSubstrate1stPiolaKirchhoffTensor[mirroredIndex];
if ((substrate.frobenius_norm() - mirroredSubstrate.frobenius_norm())/mirroredSubstrate.frobenius_norm() > 0.05) {
std::cerr << "The elements with center " << element.geometry().center()
<< " and " << elementCenter << " have different 1st-Piola-Kirchhoff stress values (assembled using order 3): " << std::endl
<< substrate << " and " << mirroredSubstrate << ", but should have the same!" << std::endl;
return 1;
}
auto shell = stressShellBiotTensor[thisIndex];
auto mirroredShell = stressShellBiotTensor[mirroredIndex];
if ((shell.frobenius_norm()-mirroredShell.frobenius_norm())/mirroredShell.frobenius_norm() > 0.05) {
std::cerr << "The elements with center " << element.geometry().center()
<< " and " << elementCenter << " have different Biot stress values (assembled using order 3): " << std::endl
<< shell << " and " << mirroredShell << ", but should have the same!" << std::endl;
return 1;
}
auto substrateNotSymmetric = stressSubstrate1stPiolaKirchhoffTensorNotSymmetric[thisIndex];
auto mirroredSubstrateNotSymmetric = stressSubstrate1stPiolaKirchhoffTensorNotSymmetric[mirroredIndex];
substrateNotSymmetric -= mirroredSubstrateNotSymmetric;
substrateModifiedIsNotSymmetric = substrateModifiedIsNotSymmetric or substrateNotSymmetric.frobenius_norm()/mirroredSubstrateNotSymmetric.frobenius_norm() > 0.05;
auto shellNotSymmetric = stressShellBiotTensorNotSymmetric[thisIndex];
auto mirroredShellNotSymmetric = stressShellBiotTensorNotSymmetric[mirroredIndex];
shellNotSymmetric -= mirroredShellNotSymmetric;
shellModifiedIsNotSymmetric = shellModifiedIsNotSymmetric or shellNotSymmetric.frobenius_norm()/mirroredShellNotSymmetric.frobenius_norm() > 0.05;
}
if (substrateModifiedIsNotSymmetric and shellModifiedIsNotSymmetric)
return 0;
std::cerr << "The modified functions still returned symmetric stress values!" << std::endl;
return 1;