Skip to content
Snippets Groups Projects
Forked from agnumpde / dune-tectonic
166 commits ahead of the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
cuboidgridconstructor.hh 7.60 KiB
#ifndef SRC_CUBOIDGRIDCONSTRUCTOR_HH
#define SRC_CUBOIDGRIDCONSTRUCTOR_HH

#include <dune/common/fmatrix.hh>
#include <dune/grid/common/gridfactory.hh>
#include <dune/grid/utility/structuredgridfactory.hh>

#include <dune/fufem/boundarypatch.hh>
#include <dune/fufem/geometry/convexpolyhedron.hh>

#include "cuboidgeometry.hh"
#include "gridconstructor.hh"
#include "simplexmanager.hh"

// -------------------------------------------------
// MyFaces
// -------------------------------------------------

template <class GridView> struct MyFaces {
  BoundaryPatch<GridView> lower;
  BoundaryPatch<GridView> right;
  BoundaryPatch<GridView> upper;
  BoundaryPatch<GridView> left;

#if MY_DIM == 3
  BoundaryPatch<GridView> front;
  BoundaryPatch<GridView> back;
#endif

  MyFaces(GridView const &gridView, const CuboidGeometry<typename GridView::ctype>& cuboidGeometry_) :
    #if MY_DIM == 3
          lower(gridView),
          right(gridView),
          upper(gridView),
          left(gridView),
          front(gridView),
          back(gridView),
    #else
          lower(gridView),
          right(gridView),
          upper(gridView),
          left(gridView),
    #endif
          cuboidGeometry(cuboidGeometry_)
    {
      lower.insertFacesByProperty([&](typename GridView::Intersection const &in) {
        return xyBetween(cuboidGeometry.lowerLeft(), cuboidGeometry.lowerRight(), in.geometry().center());
      });

      right.insertFacesByProperty([&](typename GridView::Intersection const &in) {
        return xyBetween(cuboidGeometry.lowerRight(), cuboidGeometry.upperRight(), in.geometry().center());
      });

      upper.insertFacesByProperty([&](typename GridView::Intersection const &in) {
        return xyBetween(cuboidGeometry.upperLeft(), cuboidGeometry.upperRight(), in.geometry().center());
      });

      left.insertFacesByProperty([&](typename GridView::Intersection const &in) {
        return xyBetween(cuboidGeometry.lowerLeft(), cuboidGeometry.upperLeft(), in.geometry().center());
      });

    #if MY_DIM == 3
      front.insertFacesByProperty([&](typename GridView::Intersection const &in) {
        return isClose(cuboidGeometry.depth() / 2.0, in.geometry().center()[2]);
      });

      back.insertFacesByProperty([&](typename GridView::Intersection const &in) {
        return isClose(-cuboidGeometry.depth() / 2.0, in.geometry().center()[2]);
      });
    #endif
  }

private:
  const CuboidGeometry<typename GridView::ctype>& cuboidGeometry;

  bool isClose(double a, double b) {
    return std::abs(a - b) < 1e-14 * cuboidGeometry.lengthScale();
  }

  bool isClose2(double a, double b) {
    return std::abs(a - b) <
           1e-14 * cuboidGeometry.lengthScale() * cuboidGeometry.lengthScale();
  }

  template <class Vector>
  bool xyBoxed(Vector const &v1, Vector const &v2, Vector const &x) {
      auto const minmax0 = std::minmax(v1[0], v2[0]);
      auto const minmax1 = std::minmax(v1[1], v2[1]);

      if (minmax0.first - 1e-14 * cuboidGeometry.lengthScale() > x[0] or
          x[0] > minmax0.second + 1e-14 * cuboidGeometry.lengthScale())
        return false;
      if (minmax1.first - 1e-14 * cuboidGeometry.lengthScale() > x[1] or
          x[1] > minmax1.second + 1e-14 * cuboidGeometry.lengthScale())
        return false;

      return true;
  }

  template <class Vector>
  bool xyCollinear(Vector const &a, Vector const &b, Vector const &c) {
      return isClose2((b[0] - a[0]) * (c[1] - a[1]), (b[1] - a[1]) * (c[0] - a[0]));
  }

  template <class Vector>
  bool xyBetween(Vector const &v1, Vector const &v2, Vector const &x) {
      return xyCollinear(v1, v2, x) && xyBoxed(v1, v2, x);
  }
};


template <class GridView>
MyFaces<GridView> constructFaces(const GridView& gridView, const CuboidGeometry<typename GridView::ctype>& cuboidGeometry) {
  return MyFaces<GridView>(gridView, cuboidGeometry);
}

// -------------------------------------------------
// CuboidGridConstructor
// -------------------------------------------------

template <class Grid>
class CuboidGridConstructor : public GridConstructor<Grid> {
public:
  CuboidGridConstructor(const CuboidGeometry<typename Grid::ctype>& cuboidGeometry) :
    cuboidGeometry_(cuboidGeometry) {

    createGrid();
  }

protected:
  void createGrid() {
    Dune::GridFactory<Grid> gridFactory;

    const auto& A = cuboidGeometry_.lowerLeft();
    const auto& B = cuboidGeometry_.lowerRight();
            const auto& C = cuboidGeometry_.upperRight();
            const auto& D = cuboidGeometry_.upperLeft();

            unsigned int const vc = 4;
            #if MY_DIM == 3
                Dune::FieldMatrix<double, 2 * vc, MY_DIM> vertices;
            #else
                Dune::FieldMatrix<double, vc, MY_DIM> vertices;
            #endif
                for (size_t i = 0; i < 2; ++i) {
            #if MY_DIM == 3
                  size_t numXYplanes = 2;
            #else
                  size_t numXYplanes = 1;
            #endif
                  size_t k = 0;
                  for (size_t j = 1; j <= numXYplanes; ++j) {
                    vertices[k++][i] = A[i];
                    vertices[k++][i] = B[i];
                    vertices[k++][i] = C[i];
                    vertices[k++][i] = D[i];
                    assert(k == j * vc);
                  }
                }

            #if MY_DIM == 3
                for (size_t k = 0; k < vc; ++k) {
                  vertices[k][2] = -cuboidGeometry_.depth() / 2.0;
                  vertices[k + vc][2] = cuboidGeometry_.depth() / 2.0;
                }
            #endif

                for (size_t i = 0; i < vertices.N(); ++i)
                  gridFactory.insertVertex(vertices[i]);

                Dune::GeometryType cell;
            #if MY_DIM == 3
                cell = Dune::GeometryTypes::tetrahedron;
            #else
                cell = Dune::GeometryTypes::triangle;
            #endif

            #if MY_DIM == 3
                SimplexManager sm(vc);
            #else
                SimplexManager sm;
            #endif
                sm.addFromVerticesFFB(1, 2, 0);
                sm.addFromVerticesFFB(2, 3, 0);
                auto const &simplices = sm.getSimplices();

                // sanity-check choices of simplices
                for (size_t i = 0; i < simplices.size(); ++i) {
                  Dune::FieldMatrix<double, MY_DIM, MY_DIM> check;
                  for (size_t j = 0; j < MY_DIM; ++j)
                    check[j] = vertices[simplices[i][j + 1]] - vertices[simplices[i][j]];
                  assert(check.determinant() > 0);
                  gridFactory.insertElement(cell, simplices[i]);
                }

                this->grid_ = std::shared_ptr<Grid>(gridFactory.createGrid());
                this->grid_->setRefinementType(Grid::RefinementType::COPY);
              }

    protected:
        const CuboidGeometry<typename Grid::ctype>& cuboidGeometry_;
};


// -------------------------------------------------
// DefaultCuboidGridConstructor
// -------------------------------------------------
template <class Grid>
class DefaultCuboidGridConstructor : public GridConstructor<Grid> {
  static const int dim = Grid::dimension;

public:
  DefaultCuboidGridConstructor(const CuboidGeometry<typename Grid::ctype>& cuboidGeometry, std::array<unsigned int, dim> elements) :
    cuboidGeometry_(cuboidGeometry),
    elements_(elements) {

    createGrid();
  }

protected:
  void createGrid() {
       this->grid_ = Dune::StructuredGridFactory<Grid>::createSimplexGrid(
           cuboidGeometry_.lowerLeft(), cuboidGeometry_.upperRight(), elements_);
    }

    protected:
        const CuboidGeometry<typename Grid::ctype>& cuboidGeometry_;
        std::array<unsigned int, dim> elements_;
};

#endif