Commit 68b219a9 authored by Dennis Gläser's avatar Dennis Gläser
Browse files

[entitynetwork] restructure networks and builders

Instead of storing both a list and a map, we now only store maps of
entity/subdomain fragments -> unique identifiers in order to reduce the
memory overhead. Moreover, the public interface of the entity networks
is changed such that one can no longer get fragments of a sub-domain
with a specific id as the overall map already contains this information.
This can be added in the future as an external function to extract data
of a specific subdomain from the network. The builder classes are also
restructured to no longer store unneccesary data. Only the public
interfaces of entity networks have changed, and due to the small
user-base, and as that interface is currently only used internally by
the writer (which has been modified), we don't guarantee backwards
compatibility here.
parent 596294a1
......@@ -51,62 +51,39 @@ class ContainedEntityNetwork
{
public:
//! The type of underlying map from shape to primary entity index
using typename ContainedEntityNetworkInterface::ShapeMap;
/*!
* \brief Constructor.
* \param entityDim Dimension of the network entities
* \param sdFragments The sub-domains, split into fragments by the entities
* \param entityFragments Contains the entity fragments of each sub-domain
* \param entityFragmentMaps Map containing the fragments of the sub-domains,
* where each fragment is mapped to the index of the
* primary entity of the network from which is was created.
* \param sdFragmentsMap The map of subdomain fragments -> subdomain index
* \param entityFragmentsMap The map of entity fragments -> primary entity index
*/
ContainedEntityNetwork(int entityDim,
int domainDim,
std::unordered_map<std::size_t, TopTools_ListOfShape>&& sdFragments,
std::unordered_map<std::size_t, TopTools_ListOfShape>&& entityFragments,
std::unordered_map<std::size_t, TopTools_DataMapOfShapeInteger>&& entityFragmentMaps)
ShapeMap&& sdFragmentsMap,
ShapeMap&& entityFragmentsMap)
: ContainedEntityNetworkInterface(entityDim, domainDim)
, subDomainFragments_(std::move(sdFragments))
, subDomainEntityFragments_(std::move(entityFragments))
, subDomainEntityFragmentIndexMap_(std::move(entityFragmentMaps))
{
subDomainIds_.reserve(subDomainFragments_.size());
for (const auto& sdDataPair : subDomainFragments_)
subDomainIds_.emplace_back(sdDataPair.first);
}
/*!
* \brief Returns the ids of defined the sub-domains
*/
const std::vector<Id>& subDomainIds() const override
{ return subDomainIds_; }
/*!
* \brief Returns the fragments of a sub-domain
* \param subDomainId The id of the sub-domain
*/
const TopTools_ListOfShape& subDomainFragments(Id subDomainId) const override
{ return subDomainFragments_.at(subDomainId.get()); }
, subDomainFragmentsMap_(std::move(sdFragmentsMap))
, entityFragmentsMap_(std::move(entityFragmentsMap))
{}
/*!
* \brief Returns the entity fragments of the network defined for a sub-domain
* \param subDomainId The id of the sub-domain
* \brief Returns the subdomain fragments map
*/
const TopTools_ListOfShape& subDomainEntityFragments(Id subDomainId) const override
{ return subDomainEntityFragments_.at(subDomainId.get()); }
const ShapeMap& subDomainFragmentsMap() const override
{ return subDomainFragmentsMap_; }
/*!
* \brief Returns the map which maps each fragment the network of a sub-domain to its primary entity index.
* \param subDomainId The id of the sub-domain
* \brief Returns the entity fragments map of the network
*/
const TopTools_DataMapOfShapeInteger& subDomainEntityFragmentsIndexMap(Id subDomainId) const override
{ return subDomainEntityFragmentIndexMap_.at(subDomainId.get()); }
const ShapeMap& entityFragmentsMap() const override
{ return entityFragmentsMap_; }
private:
std::unordered_map<std::size_t, TopTools_ListOfShape> subDomainFragments_;
std::unordered_map<std::size_t, TopTools_ListOfShape> subDomainEntityFragments_;
std::unordered_map<std::size_t, TopTools_DataMapOfShapeInteger> subDomainEntityFragmentIndexMap_;
std::vector<Id> subDomainIds_;
ShapeMap subDomainFragmentsMap_;
ShapeMap entityFragmentsMap_;
};
} // end namespace Frackit
......
......@@ -28,10 +28,6 @@
#include <vector>
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopoDS_Shape.hxx>
#include <frackit/common/id.hh>
namespace Frackit {
......@@ -44,6 +40,9 @@ class ContainedEntityNetworkInterface
{
public:
//! export underlying map type
using ShapeMap = TopTools_DataMapOfShapeInteger;
//! Abstract base classes need virtual destructors
virtual ~ContainedEntityNetworkInterface() {}
......@@ -71,27 +70,14 @@ public:
{ return domainDimension_; }
/*!
* \brief Returns the ids of defined the sub-domains
*/
virtual const std::vector<Id>& subDomainIds() const = 0;
/*!
* \brief Returns the fragments of a sub-domain
* \param subDomainId The id of the sub-domain
*/
virtual const TopTools_ListOfShape& subDomainFragments(Id subDomainId) const = 0;
/*!
* \brief Returns the entity fragments of the network defined for a sub-domain
* \param subDomainId The id of the sub-domain
* \brief Returns the fragments map of the subdomains
*/
virtual const TopTools_ListOfShape& subDomainEntityFragments(Id subDomainId) const = 0;
virtual const ShapeMap& subDomainFragmentsMap() const = 0;
/*!
* \brief Returns the map which maps each fragment the network of a sub-domain to its primary entity index.
* \param subDomainId The id of the sub-domain
* \brief Returns the entity fragments map of the network
*/
virtual const TopTools_DataMapOfShapeInteger& subDomainEntityFragmentsIndexMap(Id subDomainId) const = 0;
virtual const ShapeMap& entityFragmentsMap() const = 0;
private:
int entityDimension_;
......
......@@ -26,8 +26,6 @@
#define FRACKIT_ENTITY_NETWORK_HH
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopoDS_Shape.hxx>
#include "entitynetworkinterface.hh"
......@@ -48,38 +46,31 @@ class EntityNetwork
{
public:
//! The type of underlying map from shape to primary entity index
using typename EntityNetworkInterface::ShapeMap;
/*!
* \brief Constructor.
* \param entityDim Dimension of the network entities
* \param fragmentList List containing all entity fragments
* \param fragmentIndexMap Map containing the fragments
* of a network, where each fragment
* is mapped to the index of the primary
* \param fragmentMap Map containing the fragments of a network, where each
* fragment is mapped to the index of the primary
* entity of the network (before fragmentation).
*/
EntityNetwork(int entityDim,
TopTools_ListOfShape&& fragmentList,
TopTools_DataMapOfShapeInteger&& fragmentIndexMap)
ShapeMap&& fragmentMap)
: EntityNetworkInterface(entityDim)
, entityFragments_(std::move(fragmentList))
, entityFragmentIndexMap_(std::move(fragmentIndexMap))
, entityFragmentsMap_(std::move(fragmentMap))
{}
/*!
* \brief Returns the fragments of the network entities.
*/
const TopTools_ListOfShape& entityFragments() const override
{ return entityFragments_; }
/*!
* \brief Returns the map which maps each fragment to its primary entity index.
* \brief The map with all fragments of the network, where
* each fragment is mapped to the original entity index.
*/
const TopTools_DataMapOfShapeInteger& entityFragmentsIndexMap() const override
{ return entityFragmentIndexMap_; }
virtual const ShapeMap& entityFragmentsMap() const override
{ return entityFragmentsMap_; }
private:
TopTools_ListOfShape entityFragments_;
TopTools_DataMapOfShapeInteger entityFragmentIndexMap_;
ShapeMap entityFragmentsMap_;
};
} // end namespace Frackit
......
......@@ -25,8 +25,6 @@
#define FRACKIT_ENTITY_NETWORK_INTERFACE_HH
#include <TopTools_DataMapOfShapeInteger.hxx>
#include <TopTools_ListOfShape.hxx>
#include <TopoDS_Shape.hxx>
namespace Frackit {
......@@ -37,6 +35,9 @@ namespace Frackit {
class EntityNetworkInterface
{
public:
//! export underlying map type
using ShapeMap = TopTools_DataMapOfShapeInteger;
//! Abstract base classes need virtual destructors
virtual ~EntityNetworkInterface() {}
......@@ -55,14 +56,10 @@ public:
{ return entityDimension_; }
/*!
* \brief Returns the fragments of the network entities.
*/
virtual const TopTools_ListOfShape& entityFragments() const = 0;
/*!
* \brief Returns the map which maps each fragment to its primary entity index.
* \brief The map with all fragments of the network, where
* each fragment is mapped to the original entity index.
*/
virtual const TopTools_DataMapOfShapeInteger& entityFragmentsIndexMap() const = 0;
virtual const ShapeMap& entityFragmentsMap() const = 0;
private:
int entityDimension_;
......
This diff is collapsed.
......@@ -65,8 +65,7 @@ public:
if (network.entityDimension() != 2)
throw std::runtime_error("BRepWriter only implemented for 2d networks so far");
makeEntityMap_(network);
findEntityIntersectionShapes_();
findEntityIntersectionShapes_(network);
makeSubShapeMaps_(network);
makeCompound_();
}
......@@ -81,8 +80,7 @@ public:
if (network.domainDimension() != network.entityDimension() + 1)
throw std::runtime_error("BRepWriter expects entityDim = domainDim - 1");
makeEntityMap_(network);
findEntityIntersectionShapes_();
findEntityIntersectionShapes_(network);
makeSubShapeMaps_(network);
makeCompound_();
}
......@@ -104,7 +102,7 @@ protected:
* within the compound.
*/
const std::unordered_map<std::size_t, std::vector<std::size_t>>& entityToFragmentsMap() const
{ return entityToFragmentsMap_; }
{ return entityMap_; }
/*!
* \brief Returns the map that maps a primary entity intersectionindex to the
......@@ -112,7 +110,7 @@ protected:
* that intersection. The indices refer to the indices within the compound.
*/
const std::unordered_map<std::size_t, std::vector<std::size_t>>& entityIntersectionsToFragmentsMap() const
{ return entityIntersectionsToFragmentsMap_; }
{ return intersectionMap_; }
/*!
* \brief Returns the map that maps to each primary sub-domain index the list
......@@ -120,63 +118,31 @@ protected:
* that sub-domain. The indices refer to the indices within the compound.
*/
const std::unordered_map<std::size_t, std::vector<std::size_t>>& domainToFragmentsMap() const
{ return domainToFragmentsMap_; }
{ return domainMap_; }
private:
/*!
* \brief Copies all entities of a network into a single map.
* \note This overload is for contained entity networks.
*/
void makeEntityMap_(const ContainedEntityNetwork& network)
{
std::size_t subNetworkOffset = 0;
for (const auto& id : network.subDomainIds())
{
// the map maps to the entity index within the sub-domain network
// Therefore, we add the offset in order to ensure that we don't add
// entities from another network to the same primary entity index
const auto& map = network.subDomainEntityFragmentsIndexMap(id);
for (TopTools_DataMapIteratorOfDataMapOfShapeInteger it(map); it.More(); it.Next())
{
allEntities_.Append(it.Key());
allEntitiesIndexMap_.Bind(it.Key(), it.Value() + subNetworkOffset);
}
// the next sub-domain
subNetworkOffset += map.Extent();
}
}
/*!
* \brief Copies all entities of a network into a single map.
* \note This overload is for uncontained entity networks.
*/
void makeEntityMap_(const EntityNetwork& network)
{
const auto& map = network.entityFragmentsIndexMap();
for (TopTools_DataMapIteratorOfDataMapOfShapeInteger it(map); it.More(); it.Next())
{
allEntities_.Append(it.Key());
allEntitiesIndexMap_.Bind(it.Key(), it.Value());
}
}
/*!
* \brief Determins the shapes that describe intersections of entities.
*/
void findEntityIntersectionShapes_()
template<class Network>
void findEntityIntersectionShapes_(const Network& network)
{
using Iterator = typename Network::ShapeMap::Iterator;
const auto& map = network.entityFragmentsMap();
// TODO: Start second iterator from ++it, somehow. A first implementation
// of that led to some intersection edges not being meshed at the end
for (TopTools_ListIteratorOfListOfShape it(allEntities_); it.More(); it.Next())
for (Iterator it(map); it.More(); it.Next())
{
for (TopTools_ListIteratorOfListOfShape it2(allEntities_); it2.More(); it2.Next())
for (Iterator it2(map); it2.More(); it2.Next())
{
if (it.Value().IsSame(it2.Value()))
if (it.Value() == it2.Value())
continue;
const auto edges = OCCUtilities::getOverlapEdges(TopoDS::Face(it.Value()),
TopoDS::Face(it2.Value()));
const auto& f1 = TopoDS::Face(it.Key());
const auto& f2 = TopoDS::Face(it2.Key());
const auto edges = OCCUtilities::getOverlapEdges(f1, f2);
std::vector<std::size_t> handled;
for (unsigned int eIdx = 0; eIdx < edges.size(); ++eIdx)
......@@ -201,13 +167,20 @@ private:
*/
void makeSubShapeMaps_(const ContainedEntityNetwork& network)
{
for (auto id : network.subDomainIds())
for (const auto& fragment : network.subDomainFragments(id))
addSolids_(fragment, id.get());
using Iterator = typename ContainedEntityNetwork::ShapeMap::Iterator;
for (Iterator it(network.subDomainFragmentsMap()); it.More(); it.Next())
addSubDomain_(network.entityDimension()+1, it.Key(), it.Value());
for (Iterator it(network.entityFragmentsMap()); it.More(); it.Next())
addEntity_(network.entityDimension(), it.Key(), it.Value());
for (auto id : network.subDomainIds())
for (const auto& fragment : network.subDomainEntityFragments(id))
addFaces_(fragment);
std::size_t isIdx = 1;
for (const auto& isShapeList : entityIntersections_)
{
for (const auto& isShape : isShapeList)
addIntersection_(network.entityDimension()-1, isShape, isIdx);
isIdx++;
}
}
/*!
......@@ -216,138 +189,173 @@ private:
*/
void makeSubShapeMaps_(const EntityNetwork& network)
{
for (const auto& fragment : network.entityFragments())
addFaces_(fragment);
using Iterator = typename ContainedEntityNetwork::ShapeMap::Iterator;
for (Iterator it(network.entityFragmentsMap()); it.More(); it.Next())
addEntity_(network.entityDimension(), it.Key(), it.Value());
std::size_t isIdx = 1;
for (const auto& isShapeList : entityIntersections_)
{
for (const auto& isShape : isShapeList)
addIntersection_(network.entityDimension()-1, isShape, isIdx);
isIdx++;
}
}
/*!
* \brief Construct the single compound describing the network.
* \brief Add a domain of a network to the sub-shape maps.
*/
void makeCompound_()
void addSubDomain_(int domainDim, const TopoDS_Shape& shape, std::size_t id)
{
BRep_Builder b;
b.MakeCompound(compound_);
if (domainDim == 3) addSolids_(shape, domainMap_[id]);
else if (domainDim == 2) addFaces_(shape, domainMap_[id]);
else throw std::runtime_error("Unsupported domain dimension");
}
// use Standard_Integer (as OCC uses this type) instead of
// std::size_t here to avoid compiler warning
for(Standard_Integer i = 1; i <= vmap_.Extent(); i++) b.Add(compound_, vmap_(i));
for(Standard_Integer i = 1; i <= emap_.Extent(); i++) b.Add(compound_, emap_(i));
for(Standard_Integer i = 1; i <= wmap_.Extent(); i++) b.Add(compound_, wmap_(i));
for(Standard_Integer i = 1; i <= fmap_.Extent(); i++) b.Add(compound_, fmap_(i));
for(Standard_Integer i = 1; i <= shmap_.Extent(); i++) b.Add(compound_, shmap_(i));
for(Standard_Integer i = 1; i <= somap_.Extent(); i++) b.Add(compound_, somap_(i));
/*!
* \brief Add an entity of a network to the sub-shape maps.
*/
void addEntity_(int entityDim, const TopoDS_Shape& shape, std::size_t id)
{
if (entityDim == 2) addFaces_(shape, entityMap_[id]);
else if (entityDim == 1) addEdges_(shape, entityMap_[id]);
else throw std::runtime_error("Unsupported entity dimension");
}
/*!
* \brief Add an intersection of a network to the sub-shape maps.
*/
void addIntersection_(int isDim, const TopoDS_Shape& shape, std::size_t id)
{
if (isDim == 1) addEdges_(shape, intersectionMap_[id]);
else if (isDim == 0) addVertices_(shape, intersectionMap_[id]);
else throw std::runtime_error("Unsupported entity dimension");
}
/*!
* \brief Add solids to the sub-shape maps
* \param shape The shape of which the solids are to be extracted
* \param subDomainIdx The index of the sub-domain these solids are embedded in
* \param idxList List to which to append the indices of the solids
* of the given shape within the local maps.
*/
void addSolids_(const TopoDS_Shape& shape, std::size_t subDomainIdx)
void addSolids_(const TopoDS_Shape& shape, std::vector<std::size_t>& idxList)
{
for(TopExp_Explorer solidExp(shape, TopAbs_SOLID); solidExp.More(); solidExp.Next())
for (TopExp_Explorer solidExp(shape, TopAbs_SOLID); solidExp.More(); solidExp.Next())
{
TopoDS_Solid solid = TopoDS::Solid(solidExp.Current());
if(somap_.FindIndex(solid) < 1) // solid not yet in map
{
const auto curEntityIdx = somap_.Add(solid);
domainToFragmentsMap_[subDomainIdx].push_back(curEntityIdx);
const auto mapIndex = somap_.FindIndex(solid);
for(TopExp_Explorer shellExp(solid, TopAbs_SHELL); shellExp.More(); shellExp.Next())
if (mapIndex < 1)
{
idxList.push_back(somap_.Add(solid));
for (TopExp_Explorer shellExp(solid, TopAbs_SHELL); shellExp.More(); shellExp.Next())
{
TopoDS_Shell shell = TopoDS::Shell(shellExp.Current());
if(shmap_.FindIndex(shell) < 1)
if (shmap_.FindIndex(shell) < 1)
{
shmap_.Add(shell);
addFaces_(shellExp.Current());
std::vector<std::size_t> dump;
addFaces_(shellExp.Current(), dump);
}
}
}
else
idxList.push_back(mapIndex);
}
}
/*!
* \brief Add faces to the sub-shape maps
* \param shape The shape of which the faces are to be extracted
* \todo TODO: For support of 1d networks (in 2d space) we would have
* to add an overload taking the sub-domain index which is used
* in that case and which would not search for the entity index.
* \param idxList List to which to append the indices of the faces
* of the given shape within the local maps.
*/
void addFaces_(const TopoDS_Shape& shape)
void addFaces_(const TopoDS_Shape& shape, std::vector<std::size_t>& idxList)
{
for(TopExp_Explorer faceExp(shape, TopAbs_FACE); faceExp.More(); faceExp.Next())
{
TopoDS_Face face = TopoDS::Face(faceExp.Current());
const auto faceIdx = fmap_.FindIndex(face);
const auto mapIndex = fmap_.FindIndex(face);
if (faceIdx < 1)
if (mapIndex < 1)
{
const auto curEntityIdx = fmap_.Add(face);
int entityIdx;
if (allEntitiesIndexMap_.Find(faceExp.Current(), entityIdx))
entityToFragmentsMap_[entityIdx].push_back(curEntityIdx);
idxList.push_back(fmap_.Add(face));
for (TopExp_Explorer wireExp(face.Oriented(TopAbs_FORWARD), TopAbs_WIRE); wireExp.More(); wireExp.Next())
{
TopoDS_Wire wire = TopoDS::Wire(wireExp.Current());
if(wmap_.FindIndex(wire) < 1)
if (wmap_.FindIndex(wire) < 1)
{
wmap_.Add(wire);
addEdges_(wireExp.Current());
std::vector<std::size_t> dump;
addEdges_(wireExp.Current(), dump);
}
}
}
else
idxList.push_back(mapIndex);
}
}
/*!
* \brief Add edges to the sub-shape maps
* \param shape The shape of which the edges are to be extracted
* \todo TODO: For support of 1d networks (in 2d space) we would have
* to distinguish here and search for the entity index instead
* of the intersection index.
* \param idxList List to which to append the indices of the edges
* of the given shape within the local maps.
*/
void addEdges_(const TopoDS_Shape& shape)
void addEdges_(const TopoDS_Shape& shape, std::vector<std::size_t>& idxList)
{
for (TopExp_Explorer edgeExp(shape, TopAbs_EDGE); edgeExp.More(); edgeExp.Next())
{
TopoDS_Edge edge = TopoDS::Edge(edgeExp.Current());
const auto edgeIdx = emap_.FindIndex(edge);
const auto mapIndex = emap_.FindIndex(edge);
if(edgeIdx < 1)
if (mapIndex < 1)
{
const auto curEntityIdx = emap_.Add(edge);
// start from index 1 in the map
for (std::size_t isIdx = 0; isIdx < entityIntersections_.size(); ++isIdx)
if (entityIntersections_[isIdx].Contains(edge))
entityIntersectionsToFragmentsMap_[isIdx+1].push_back(curEntityIdx);
addVertices_(edgeExp.Current());
idxList.push_back(emap_.Add(edge));
std::vector<std::size_t> dump;
addVertices_(edgeExp.Current(), dump);
}
else
idxList.push_back(mapIndex);
}
}
/*!
* \brief Add vertices to the sub-shape maps
* \param shape The shape of which the vertices are to be extracted
* \todo TODO: For support of 1d networks (in 2d space) we would have
* to check if the vertices describe entity intersections.
* \param idxList List to which to append the indices of the vertices
* of the given shape within the local maps.
*/
void addVertices_(const TopoDS_Shape& shape)
void addVertices_(const TopoDS_Shape& shape, std::vector<std::size_t>& idxList)
{
for (TopExp_Explorer vertExp(shape, TopAbs_VERTEX); vertExp.More(); vertExp.Next())
{
TopoDS_Vertex vertex = TopoDS::Vertex(vertExp.Current());
if(vmap_.FindIndex(vertex) < 1)
vmap_.Add(vertex);
const auto mapIndex = vmap_.FindIndex(vertex);
if (mapIndex < 1) idxList.push_back(vmap_.Add(vertex));
else idxList.push_back(mapIndex);
}
}
/*!
* \brief Construct the single compound describing the network.
*/
void makeCompound_()
{
BRep_Builder b;
b.MakeCompound(compound_);
// use Standard_Integer (as OCC uses this type) instead of
// std::size_t here to avoid compiler warning
for(Standard_Integer i = 1; i <= vmap_.Extent(); i++) b.Add(compound_, vmap_(i));
for(Standard_Integer i = 1; i <= emap_.Extent(); i++) b.Add(compound_, emap_(i));
for(Standard_Integer i = 1; i <= wmap_.Extent(); i++) b.Add(compound_, wmap_(i));
for(Standard_Integer i = 1; i <= fmap_.Extent(); i++) b.Add(compound_, fmap_(i));
for(Standard_Integer i = 1; i <= shmap_.Extent(); i++) b.Add(compound_, shmap_(i));
for(Standard_Integer i = 1; i <= somap_.Extent(); i++) b.Add(compound_, somap_(i));
}
// containers to store the primary entities
TopTools_ListOfShape allEntities_;