15#ifndef DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_PROJECTION_HH 
   16#define DUMUX_MULTIDOMAIN_EMBEDDED_COUPLINGMANAGER_1D3D_PROJECTION_HH 
   22#include <dune/common/timer.hh> 
   23#include <dune/common/exceptions.hh> 
   24#include <dune/common/fvector.hh> 
   25#include <dune/geometry/quadraturerules.hh> 
   52template <
class Gr
idGeometry>
 
   55    using GridView = 
typename GridGeometry::GridView;
 
   56    using GlobalPosition = 
typename GridView::template Codim<0>::Geometry::GlobalCoordinate;
 
   67    template <
class RadiusFunction>
 
   70        const auto& gridView = gg.gridView();
 
   71        segments_.resize(gridView.size(0));
 
   72        for (
const auto &element : elements(gridView))
 
   74            const auto geometry = element.geometry();
 
   75            const auto eIdx = gg.elementMapper().index(element);
 
   76            const auto radius = radiusFunction(eIdx);
 
   78            segments_[eIdx] = Segment{ geometry.corner(0), geometry.corner(1), 
radius, eIdx };
 
   81        std::cout << 
"-- Extracted " << segments_.size() << 
" segments.\n";
 
 
   86    { 
return segments_[eIdx].r; }
 
 
   89    const auto& 
segment(std::size_t eIdx)
 const 
   90    { 
return segments_[eIdx]; }
 
 
  101        double minSignedDist = std::numeric_limits<double>::max();
 
  103        for (
const auto &
segment : segments_)
 
  105            const auto signedDist = computeSignedDistance_(globalPos, 
segment);
 
  106            if (signedDist < minSignedDist)
 
  108                minSignedDist = signedDist;
 
  114        return std::make_tuple(eIdx, abs(minSignedDist));
 
 
  118    template <
class IndexRange>
 
  120                                   const IndexRange& segIndices)
 const 
  123        double minSignedDist = std::numeric_limits<double>::max();
 
  125        for (
const auto index : segIndices)
 
  127            const auto &
segment = segments_[index];
 
  128            const auto signedDist = computeSignedDistance_(globalPos, 
segment);
 
  129            if (signedDist < minSignedDist)
 
  131                minSignedDist = signedDist;
 
  137        return std::make_tuple(eIdx, abs(minSignedDist));
 
 
  143        const auto& 
segment = segments_[idx];
 
 
  151    GlobalPosition projectionPointOnSegment_(
const GlobalPosition& p, 
const GlobalPosition& a, 
const GlobalPosition& b)
 const 
  153        const auto v = b - a;
 
  154        const auto w = p - a;
 
  156        const auto proj1 = v*
w;
 
  160        const auto proj2 = v.two_norm2();
 
  164        const auto t = proj1 / proj2;
 
  171    auto computeSignedDistance_(
const GlobalPosition& p, 
const Segment& 
segment)
 const 
  173        const auto projPoint = projectionPointOnSegment_(p, 
segment.a, 
segment.b);
 
  174        return (p-projPoint).two_norm()-
segment.r;
 
  177    std::vector<Segment> segments_;
 
 
  186template<
class Network>
 
  197        const auto& [closestSegmentIdx, _] = network_.findClosestSegmentSurface(pos);
 
  198        return closestSegmentIdx;
 
 
  201    template <
class Pos, 
class H
intContainer>
 
  202    auto operator()(
const Pos& pos, 
const HintContainer& hints)
 const 
  204        const auto& [closestSegmentIdx, _] = network_.findClosestSegmentSurface(pos, hints);
 
  205        return closestSegmentIdx;
 
 
  209    const Network& network_;
 
 
  219    void push(
const std::array<Dune::FieldVector<double, 3>, 3>& corners, 
double data)
 
  221        vtkCells_.emplace_back(std::array<std::size_t, 3>{
 
  222            { vtkPoints_.size(), vtkPoints_.size()+1, vtkPoints_.size()+2 }
 
  224        for (
const auto& c : corners)
 
  225            vtkPoints_.push_back(c);
 
  226        vtkCellData_.push_back(data);
 
 
  231        std::ofstream intersectionFile(name);
 
  232        intersectionFile << 
"# vtk DataFile Version 2.0\n";
 
  233        intersectionFile << 
"Really cool intersection data\n";
 
  234        intersectionFile << 
"ASCII\n";
 
  235        intersectionFile << 
"DATASET UNSTRUCTURED_GRID\n";
 
  236        intersectionFile << 
"POINTS " << vtkPoints_.size() << 
" float\n";
 
  237        for (
const auto& p : vtkPoints_)
 
  238            intersectionFile << p[0] << 
" " << p[1] << 
" " << p[2] << 
"\n";
 
  239        intersectionFile << 
"\nCELLS " << vtkCells_.size() << 
" " << vtkCells_.size()*4 << 
"\n";
 
  240        for (
const auto& c : vtkCells_)
 
  241            intersectionFile << 
"3 " << c[0] << 
" " << c[1] << 
" " << c[2] << 
"\n";
 
  242        intersectionFile << 
"\nCELL_TYPES " << vtkCells_.size() << 
"\n";
 
  243        for (
int i = 0; i < vtkCells_.size(); ++i)
 
  244            intersectionFile << 
"5\n";
 
  245        intersectionFile << 
"\nCELL_DATA " << vtkCells_.size() << 
"\nSCALARS index float\nLOOKUP_TABLE default\n";
 
  246        for (
const auto& c : vtkCellData_)
 
  247            intersectionFile << c << 
"\n";
 
 
  251    std::vector<Dune::FieldVector<double, 3>> vtkPoints_;
 
  252    std::vector<std::array<std::size_t, 3>> vtkCells_;
 
  253    std::vector<double> vtkCellData_;
 
 
  258namespace Embedded1d3dCouplingMode {
 
  260    static std::string 
name() { 
return "projection"; }
 
 
  267template<
class MDTraits, 
class CouplingMode>
 
  268class Embedded1d3dCouplingManager;
 
  318template<
class MDTraits>
 
  319class Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Projection>
 
  320: 
public EmbeddedCouplingManagerBase<MDTraits, Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Projection>>
 
  322    using ThisType = Embedded1d3dCouplingManager<MDTraits, Embedded1d3dCouplingMode::Projection>;
 
  323    using ParentType = EmbeddedCouplingManagerBase<MDTraits, ThisType>;
 
  325    using Scalar = 
typename MDTraits::Scalar;
 
  326    using SolutionVector = 
typename MDTraits::SolutionVector;
 
  327    using PointSourceData = 
typename ParentType::PointSourceTraits::PointSourceData;
 
  329    static constexpr auto bulkIdx = 
typename MDTraits::template SubDomain<0>::Index();
 
  330    static constexpr auto lowDimIdx = 
typename MDTraits::template SubDomain<1>::Index();
 
  333    template<std::
size_t id> 
using SubDomainTypeTag = 
typename MDTraits::template SubDomain<id>::TypeTag;
 
  334    template<std::
size_t id> 
using Problem = GetPropType<SubDomainTypeTag<id>, Properties::Problem>;
 
  335    template<std::
size_t id> 
using GridGeometry = GetPropType<SubDomainTypeTag<id>, Properties::GridGeometry>;
 
  336    template<std::
size_t id> 
using GridView = 
typename GridGeometry<id>::GridView;
 
  337    template<std::
size_t id> 
using Element = 
typename GridView<id>::template Codim<0>::Entity;
 
  338    template<std::
size_t id> 
using GridIndex = 
typename IndexTraits<GridView<id>>::GridIndex;
 
  340    static constexpr int lowDimDim = GridView<lowDimIdx>::dimension;
 
  341    static constexpr int bulkDim = GridView<bulkIdx>::dimension;
 
  342    static constexpr int dimWorld = GridView<bulkIdx>::dimensionworld;
 
  344    template<std::
size_t id>
 
  345    static constexpr bool isBox()
 
  348    using GlobalPosition = 
typename Element<bulkIdx>::Geometry::GlobalCoordinate;
 
  350    using SegmentNetwork = Detail::SegmentNetwork<GridGeometry<lowDimIdx>>;
 
  353    static constexpr Embedded1d3dCouplingMode::Projection couplingMode{};
 
  355    using ParentType::ParentType;
 
  357    void init(std::shared_ptr<Problem<bulkIdx>> bulkProblem,
 
  358              std::shared_ptr<Problem<lowDimIdx>> lowDimProblem,
 
  359              const SolutionVector& curSol)
 
  361        ParentType::init(bulkProblem, lowDimProblem, curSol);
 
  372    void computePointSourceData(std::size_t order = 1, 
bool verbose = 
false)
 
  377        std::cout << 
"Initializing the coupling manager (projection)" << std::endl;
 
  380        const bool enableIntersectionOutput = 
getParam<bool>(
"MixedDimension.Projection.EnableIntersectionOutput", 
false);
 
  381        std::unique_ptr<Detail::DebugIntersectionVTKOutput> vtkCoupledFaces =
 
  382            enableIntersectionOutput ? std::make_unique<Detail::DebugIntersectionVTKOutput>() : nullptr;
 
  383        std::unique_ptr<Detail::DebugIntersectionVTKOutput> vtkIntersections =
 
  384            enableIntersectionOutput ? std::make_unique<Detail::DebugIntersectionVTKOutput>() : nullptr;
 
  388        const auto& lowDimProblem = this->problem(lowDimIdx);
 
  389        const auto& lowDimFvGridGeometry = lowDimProblem.gridGeometry();
 
  390        const auto& lowDimGridView = lowDimFvGridGeometry.gridView();
 
  391        localAreaFactor_.resize(lowDimGridView.size(0), 0.0);
 
  392        const auto radiusFunc = [&](
const GridIndex<lowDimIdx> eIdx) {
 
  393            return lowDimProblem.spatialParams().radius(eIdx);
 
  395        const auto network = SegmentNetwork{
 
  396            lowDimFvGridGeometry, radiusFunc
 
  400        this->precomputeVertexIndices(bulkIdx);
 
  401        this->precomputeVertexIndices(lowDimIdx);
 
  403        const auto& bulkProblem = this->problem(bulkIdx);
 
  404        const auto& bulkFvGridGeometry = bulkProblem.gridGeometry();
 
  405        const auto& bulkGridView = bulkFvGridGeometry.gridView();
 
  406        bulkElementMarker_.assign(bulkGridView.size(0), 0);
 
  407        bulkVertexMarker_.assign(bulkGridView.size(bulkDim), 0);
 
  411        static const auto bBoxShrinking
 
  412            = 
getParam<Scalar>(
"MixedDimension.Projection.CoupledBoundingBoxShrinkingFactor", 1e-2);
 
  413        const GlobalPosition threshold(
 
  414            bBoxShrinking*( bulkFvGridGeometry.bBoxMax()-bulkFvGridGeometry.bBoxMin() ).two_norm()
 
  416        const auto bBoxMinSmall = bulkFvGridGeometry.bBoxMin() + threshold;
 
  417        const auto bBoxMaxSmall = bulkFvGridGeometry.bBoxMax() - threshold;
 
  418        auto insideBBox = [bBoxMin=bBoxMinSmall, bBoxMax=bBoxMaxSmall](
const GlobalPosition& point) -> 
bool 
  420            static constexpr Scalar eps_ = 1.0e-7;
 
  421            const Scalar eps0 = eps_*(bBoxMax[0] - bBoxMin[0]);
 
  422            const Scalar eps1 = eps_*(bBoxMax[1] - bBoxMin[1]);
 
  423            const Scalar eps2 = eps_*(bBoxMax[2] - bBoxMin[2]);
 
  424            return (bBoxMin[0] - eps0 <= point[0] && point[0] <= bBoxMax[0] + eps0 &&
 
  425                    bBoxMin[1] - eps1 <= point[1] && point[1] <= bBoxMax[1] + eps1 &&
 
  426                    bBoxMin[2] - eps2 <= point[2] && point[2] <= bBoxMax[2] + eps2);
 
  430        static const auto quadSimplexRefineMaxLevel
 
  432        const auto indicator = Detail::NetworkIndicatorFunction { network };
 
  435        static const auto estimateNumberOfPointSources
 
  436            = 
getParam<std::size_t>(
"MixedDimension.Projection.EstimateNumberOfPointSources", bulkFvGridGeometry.gridView().size(0));
 
  438        this->pointSources(bulkIdx).reserve(estimateNumberOfPointSources);
 
  439        this->pointSources(lowDimIdx).reserve(estimateNumberOfPointSources);
 
  440        this->pointSourceData().reserve(estimateNumberOfPointSources);
 
  445        for (
const auto& element : elements(bulkGridView))
 
  447            const auto bulkElementIdx = bulkFvGridGeometry.elementMapper().index(element);
 
  448            const auto bulkGeometry = 
element.geometry();
 
  449            const auto refElement = Dune::referenceElement(element);
 
  450            for (
const auto& intersection : intersections(bulkGridView, element))
 
  453                if (!intersection.boundary())
 
  457                const auto [isCoupled, closestSegmentIdx, minDist] = isCoupled_(network, intersection, insideBBox);
 
  462                bulkElementMarker_[bulkElementIdx] = 1;
 
  464                const auto interfaceGeometry = intersection.geometry();
 
  465                for (
int i = 0; i < interfaceGeometry.corners(); ++i)
 
  467                    const auto localVIdx = refElement.subEntity(intersection.indexInInside(), 1, i, bulkDim);
 
  468                    const auto vIdx = bulkFvGridGeometry.vertexMapper().subIndex(element, localVIdx, bulkDim);
 
  469                    bulkVertexMarker_[vIdx] = 1;
 
  473                if (enableIntersectionOutput)
 
  474                    vtkCoupledFaces->push({
 
  475                        { interfaceGeometry.corner(0), interfaceGeometry.corner(1), interfaceGeometry.corner(2)}
 
  476                    }, closestSegmentIdx);
 
  478                const auto quadSimplex = LocalRefinementSimplexQuadrature{ interfaceGeometry, quadSimplexRefineMaxLevel, indicator };
 
  481                for (
const auto& qp : quadSimplex)
 
  483                    const auto surfacePoint = interfaceGeometry.global(qp.position());
 
  484                    const auto closestSegmentIdx = qp.indicator();
 
  485                    const auto projPoint = network.projectionPointOnSegment(surfacePoint, closestSegmentIdx);
 
  487                    addPointSourceAtIP_(bulkGeometry, interfaceGeometry, qp, bulkElementIdx, closestSegmentIdx, surfacePoint, projPoint);
 
  488                    addStencilEntries_(bulkElementIdx, closestSegmentIdx);
 
  494        using namespace Dune::Hybrid;
 
  495        forEach(integralRange(Dune::index_constant<2>{}), [&](
const auto domainIdx)
 
  497            for (
auto&& stencil : this->couplingStencils(domainIdx))
 
  499                std::sort(stencil.second.begin(), stencil.second.end());
 
  500                stencil.second.erase(
 
  501                    std::unique(stencil.second.begin(), stencil.second.end()),
 
  508        if (enableIntersectionOutput)
 
  509            vtkCoupledFaces->write(
"coupledfaces.vtk");
 
  513        for (
const auto& element : elements(lowDimGridView))
 
  515            const auto length = 
element.geometry().volume();
 
  516            const auto eIdx = lowDimFvGridGeometry.elementMapper().index(element);
 
  517            const auto radius = this->problem(lowDimIdx).spatialParams().radius(eIdx);
 
  518            const auto cylinderSurface = 2.0*M_PI*radius*length;
 
  519            localAreaFactor_[eIdx] /= cylinderSurface;
 
  520            localAreaFactor_[eIdx] -= 1.0;
 
  523        this->pointSources(bulkIdx).shrink_to_fit();
 
  524        this->pointSources(lowDimIdx).shrink_to_fit();
 
  525        this->pointSourceData().shrink_to_fit();
 
  527        std::cout << 
"-- Coupling at " << this->pointSourceData().size() << 
" integration points." << std::endl;
 
  528        std::cout << 
"-- Finished initialization after " << watch.elapsed() << 
" seconds." << std::endl;
 
  537    Scalar radius(std::size_t 
id)
 const 
  539        const auto& data = this->pointSourceData()[id];
 
  540        return this->problem(lowDimIdx).spatialParams().radius(data.lowDimElementIdx());
 
  546    const std::vector<int>& bulkElementMarker()
 const 
  547    { 
return bulkElementMarker_; }
 
  550    const std::vector<int>& bulkVertexMarker()
 const 
  551    { 
return bulkVertexMarker_; }
 
  556    const std::vector<Scalar>& localAreaFactor()
 const 
  557    { 
return localAreaFactor_; }
 
  560    std::vector<int> bulkElementMarker_, bulkVertexMarker_;
 
  561    std::vector<double> localAreaFactor_;
 
  565    template<
class BulkGeometry, 
class InterfaceGeometry, 
class QP>
 
  566    void addPointSourceAtIP_(
const BulkGeometry& bulkGeometry,
 
  567                             const InterfaceGeometry& ifGeometry,
 
  569                             const GridIndex<bulkIdx> bulkElementIdx,
 
  570                             const GridIndex<lowDimIdx> lowDimElementIdx,
 
  571                             const GlobalPosition& surfacePoint,
 
  572                             const GlobalPosition& projPoint)
 
  575        const auto id = this->idCounter_++;
 
  578        const auto qpweight = qp.weight();
 
  579        const auto integrationElement = ifGeometry.integrationElement(qp.position());
 
  580        this->pointSources(bulkIdx).emplace_back(surfacePoint, 
id, qpweight, integrationElement, bulkElementIdx);
 
  583        this->pointSources(lowDimIdx).emplace_back(projPoint, 
id, qpweight, integrationElement, lowDimElementIdx);
 
  584        localAreaFactor_[lowDimElementIdx] += qpweight*integrationElement;
 
  586        const auto& bulkFvGridGeometry = this->problem(bulkIdx).gridGeometry();
 
  587        const auto& lowDimFvGridGeometry = this->problem(lowDimIdx).gridGeometry();
 
  591        PointSourceData psData;
 
  593        if constexpr (isBox<lowDimIdx>())
 
  595            std::vector<Dune::FieldVector<Scalar, 1> > shapeValues;
 
  596            const auto lowDimGeometry = this->problem(lowDimIdx).gridGeometry().element(lowDimElementIdx).geometry();
 
  597            this->getShapeValues(lowDimIdx, lowDimFvGridGeometry, lowDimGeometry, projPoint, shapeValues);
 
  598            psData.addLowDimInterpolation(shapeValues, this->vertexIndices(lowDimIdx, lowDimElementIdx), lowDimElementIdx);
 
  602            psData.addLowDimInterpolation(lowDimElementIdx);
 
  605        if constexpr (isBox<bulkIdx>())
 
  607            std::vector<Dune::FieldVector<Scalar, 1> > shapeValues;
 
  608            this->getShapeValues(bulkIdx, bulkFvGridGeometry, bulkGeometry, surfacePoint, shapeValues);
 
  609            psData.addBulkInterpolation(shapeValues, this->vertexIndices(bulkIdx, bulkElementIdx), bulkElementIdx);
 
  613            psData.addBulkInterpolation(bulkElementIdx);
 
  617        this->pointSourceData().emplace_back(std::move(psData));
 
  620    void addStencilEntries_(
const GridIndex<bulkIdx> bulkElementIdx, 
const GridIndex<lowDimIdx> lowDimElementIdx)
 
  623        if constexpr (isBox<lowDimIdx>())
 
  625            const auto& vertices = this->vertexIndices(lowDimIdx, lowDimElementIdx);
 
  626            this->couplingStencils(bulkIdx)[bulkElementIdx].insert(
 
  627                this->couplingStencils(bulkIdx)[bulkElementIdx].end(),
 
  628                vertices.begin(), vertices.end()
 
  634            this->couplingStencils(bulkIdx)[bulkElementIdx].push_back(lowDimElementIdx);
 
  638        if constexpr (isBox<bulkIdx>())
 
  640            const auto& vertices = this->vertexIndices(bulkIdx, bulkElementIdx);
 
  641            this->couplingStencils(lowDimIdx)[lowDimElementIdx].insert(
 
  642                this->couplingStencils(lowDimIdx)[lowDimElementIdx].end(),
 
  643                vertices.begin(), vertices.end()
 
  648            this->couplingStencils(lowDimIdx)[lowDimElementIdx].push_back(bulkElementIdx);
 
  652    template<
class BoundaryIntersection, 
class BBoxCheck>
 
  653    auto isCoupled_(
const SegmentNetwork& network, 
const BoundaryIntersection& intersection, 
const BBoxCheck& insideBBox)
 const 
  655        const auto center = intersection.geometry().center();
 
  656        const auto [eIdx, minDist] = network.findClosestSegmentSurface(
center);
 
  660        static const bool considerBBox = 
getParam<bool>(
"MixedDimension.Projection.ConsiderFacesWithinBoundingBoxCoupled", 
false);
 
  661        if (considerBBox && insideBBox(
center))
 
  662            return std::make_tuple(
true, eIdx, minDist);
 
  666        static const auto rFactor = 
getParam<Scalar>(
"MixedDimension.Projection.CoupledRadiusFactor", 0.1);
 
  667        static const auto spFactor = 
getParam<Scalar>(
"MixedDimension.Projection.CoupledAngleFactor", 0.3);
 
  668        const auto projPoint = network.projectionPointOnSegment(
center, eIdx);
 
  669        const auto distVec = projPoint - 
center;
 
  670        const bool isCoupled = minDist < rFactor * network.radius(eIdx) && distVec * intersection.centerUnitOuterNormal() > distVec.two_norm() * spFactor;
 
  671        return std::make_tuple(isCoupled, eIdx, minDist);
 
  676template<
class MDTraits>
 
  678: 
public std::true_type {};
 
 
Simple legacy VTK writer for outputting debug data on the coupling interface.
Definition couplingmanager1d3d_projection.hh:217
void push(const std::array< Dune::FieldVector< double, 3 >, 3 > &corners, double data)
Definition couplingmanager1d3d_projection.hh:219
void write(const std::string &name)
Definition couplingmanager1d3d_projection.hh:229
NetworkIndicatorFunction(const Network &n)
Definition couplingmanager1d3d_projection.hh:190
auto operator()(const Pos &pos) const
Definition couplingmanager1d3d_projection.hh:195
auto operator()(const Pos &pos, const HintContainer &hints) const
Definition couplingmanager1d3d_projection.hh:202
auto findClosestSegmentSurface(const GlobalPosition &globalPos, const IndexRange &segIndices) const
same as overload with taking a position but only look at the segments specified by the index vector
Definition couplingmanager1d3d_projection.hh:119
const auto & segment(std::size_t eIdx) const
the segment with index eIdx
Definition couplingmanager1d3d_projection.hh:89
auto radius(std::size_t eIdx) const
Definition couplingmanager1d3d_projection.hh:85
GlobalPosition projectionPointOnSegment(const GlobalPosition &p, std::size_t idx) const
Definition couplingmanager1d3d_projection.hh:141
const auto & segments() const
the segments
Definition couplingmanager1d3d_projection.hh:93
SegmentNetwork(const GridGeometry &gg, const RadiusFunction &radiusFunction)
Definition couplingmanager1d3d_projection.hh:68
auto findClosestSegmentSurface(const GlobalPosition &globalPos) const
Definition couplingmanager1d3d_projection.hh:98
Manages the coupling between bulk elements and lower dimensional elements Point sources on each integ...
Definition couplingmanager1d3d.hh:24
Defines all properties used in Dumux.
Coupling manager for low-dimensional domains embedded in the bulk domain. Point sources on each integ...
A function to compute the convex hull of a point cloud.
Corners::value_type center(const Corners &corners)
The center of a given list of corners.
Definition center.hh:24
T getParam(Args &&... args)
A free function to get a parameter from the parameter tree singleton.
Definition parameters.hh:139
A quadrature rule using local refinement to approximate partitioned elements.
Define some often used mathematical functions.
Distance implementation details.
Definition cvfelocalresidual.hh:25
constexpr Box box
Definition method.hh:147
Definition couplingmanager1d3d_average.hh:34
constexpr Projection projection
Definition couplingmanager1d3d_projection.hh:263
const Scalar PengRobinsonMixture< Scalar, StaticParameters >::w
Definition pengrobinsonmixture.hh:140
A quadrature based on refinement.
Type trait that is specialized for coupling manager supporting multithreaded assembly.
Definition multistagemultidomainfvassembler.hh:78
Definition couplingmanager1d3d_projection.hh:259
static std::string name()
Definition couplingmanager1d3d_projection.hh:260
typename GridView::IndexSet::IndexType GridIndex
Definition indextraits.hh:27
Helper class to create (named and comparable) tagged types Tags any given type. The tagged type is eq...
Definition tag.hh:30
Helper class to create (named and comparable) tagged types.
Functionality to triangulate point clouds.