gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
SpanningTree.cpp
Go to the documentation of this file.
1 // Gmsh - Copyright (C) 1997-2022 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 // Contributed by Nicolas Marsic.
6 
7 #include <sstream>
8 #include <algorithm>
9 
10 #include "SpanningTree.h"
11 #include "GModel.h"
12 #include "MLine.h"
13 #include "OS.h"
14 
15 using namespace std;
16 
18  {GMSH_FULLRC, "OutputPhysical", nullptr, -1},
19 };
20 
22  {GMSH_FULLRC, "PhysicalVolumes", nullptr, ""},
23  {GMSH_FULLRC, "PhysicalSurfaces", nullptr, ""},
24  {GMSH_FULLRC, "PhysicalCurves", nullptr, ""},
25 };
26 
27 extern "C" {
29 {
30  return new GMSH_SpanningTreePlugin();
31 }
32 }
33 
35 
36 string GMSH_SpanningTreePlugin::getName() const { return "SpanningTree"; }
37 
39 {
40  return "Builds a tree spanning every vertex of a mesh";
41 }
42 
44 {
45  return "Plugin(SpanningTree) builds a tree spanning every vertex of a mesh "
46  "and stores it directly in the model.\n"
47  "The tree is constructed by starting first on the curves, "
48  "then on the surfaces and finally on the volumes.\n"
49  "\n"
50  "Parameters\n"
51  "- PhysicalVolumes: list of the physical volumes "
52  "upon which the tree must be built.\n"
53  "- PhysicalSurfaces: list of the physical surfaces "
54  "upon which the tree must be built.\n"
55  "- PhysicalCurves: list of the physical curves "
56  "upon which the tree must be built.\n"
57  "- OutputPhysical: physical tag of the generated tree "
58  "(-1 will select a new tag automatically).\n"
59  "\n"
60  "Note - Lists must be comma separated integers "
61  "and spaces are ignored.\n"
62  "Remark - This plugin does not overwrite a physical group."
63  "Therefore, if an existing physical tag is used in OutputPhysical, "
64  "the edges of the tree will be /added/ to the specified group.";
65 }
66 
67 string GMSH_SpanningTreePlugin::getAuthor() const { return "N. Marsic"; }
68 
70 {
71  return sizeof(SpanningTreeOptions_Number) / sizeof(StringXNumber);
72 }
73 
75 {
76  return &SpanningTreeOptions_Number[iopt];
77 }
78 
80 {
81  return sizeof(SpanningTreeOptions_String) / sizeof(StringXString);
82 }
83 
85 {
86  return &SpanningTreeOptions_String[iopt];
87 }
88 
90 {
91  // Get data
92  double time = Cpu(), w = TimeOfDay();
93  int output = (int)SpanningTreeOptions_Number[0].def;
94  string volume = SpanningTreeOptions_String[0].def;
95  string surface = SpanningTreeOptions_String[1].def;
96  string curve = SpanningTreeOptions_String[2].def;
97 
98  // Parse physical tags
99  vector<list<int> > physical(3);
100  curve = parse(curve, physical[0]);
101  surface = parse(surface, physical[1]);
102  volume = parse(volume, physical[2]);
103 
104  // Dimensions
105  int dim[3] = {1, 2, 3};
106 
107  // Get model
108  GModel *model = GModel::current();
109 
110  // Get all elements in physicals for each dimension
111  vector<ElementSet> element(3);
112  for(int i = 0; i < 3; i++)
113  for(auto j = physical[i].begin(); j != physical[i].end(); j++)
114  getAllMElement(*model, *j, dim[i], element[i]);
115 
116  // Check if we have something
117  if(element[0].empty() && element[1].empty() && element[2].empty()) {
118  Msg::Warning("No elements found in the given physcials: abording!");
119  return 0;
120  }
121 
122  // Display physicals (as [poorly] parsed)
123  Msg::Info("--> PhysicalVolumes: %s", volume.c_str());
124  Msg::Info("--> PhysicalSurfaces: %s", surface.c_str());
125  Msg::Info("--> PhysicalCurves: %s", curve.c_str());
126  Msg::Info("--> OutputPhysical: %d", output);
127 
128  // Get all edges from elements for each dimension
129  vector<EdgeSet> edge(3);
130  for(int i = 0; i < 3; i++) getAllMEdge(element[i], edge[i]);
131 
132  // Build spanning tree (in ascending dimension order) and save into the model
133  DSU vertex(model->getNumMeshVertices());
134  Tree tree;
135  for(int i = 0; i < 3; i++) spanningTree(edge[i], vertex, tree);
136 
137  addToModel(*model, tree, output);
138 
139  // Done
140  Msg::Info("Spanning tree built (Wall %gs, CPU %gs)", TimeOfDay() - w,
141  Cpu() - time);
142  return 0;
143 }
144 
146  Tree &tree)
147 {
148  // Kruskal's algorithm, without edge sorting, since we don't weight them
149 
150  // Iterate on edges
151  for(auto it = edge.begin(); it != edge.end(); it++) { // Loop on edges:
152  if(vertex.find(it->first) != vertex.find(it->second)) { // if the current
153  tree.push_back(*it); // edge connects two
154  vertex.join(it->first, it->second); // disjoint trees,
155  // use it and joint!
156  }
157  }
158 }
159 
160 string GMSH_SpanningTreePlugin::parse(string str, list<int> &physical)
161 {
162  // Remove spaces
163  str.erase(remove(str.begin(), str.end(), ' '), str.end());
164 
165  // Replace commas by spaces
166  replace(str.begin(), str.end(), ',', ' ');
167 
168  // Init string stream
169  stringstream stream;
170  stream << str;
171 
172  // Parse stream for integers
173  int tag;
174  string tmp;
175  while(!stream.eof()) {
176  stream >> tmp; // Take next 'word'
177  if(sscanf(tmp.c_str(), "%d", &tag) > 0) physical.push_back(tag);
178  }
179 
180  // Return modified string
181  return str;
182 }
183 
185  int dim, ElementSet &element)
186 {
187  std::map<int, std::vector<GEntity *> > group;
188 
189  // Get groups
190  model.getPhysicalGroups(dim, group);
191 
192  // Get entities, if any
193  auto entity = group.find(physical);
194  if(entity == group.end()) return;
195 
196  for(size_t i = 0; i < entity->second.size(); i++)
197  for(size_t j = 0; j < entity->second[i]->getNumMeshElements(); j++)
198  element.insert(entity->second[i]->getMeshElement(j));
199 }
200 
202 {
203  auto end = element.end();
204  auto it = element.begin();
205 
206  for(; it != end; it++)
207  for(int i = 0; i < (*it)->getNumEdges(); i++)
208  edge.insert(
209  std::pair<int, int>((*it)->getEdge(i).getVertex(0)->getNum() - 1,
210  (*it)->getEdge(i).getVertex(1)->getNum() - 1));
211 }
212 
213 void GMSH_SpanningTreePlugin::addToModel(GModel &model, Tree &tree, int tag)
214 {
215  // Transform Tree into MLines
216 
217  // Future MElements
218  std::vector<MElement *> line(tree.size());
219 
220  // Populate
221  auto end = tree.end();
222  auto it = tree.begin();
223 
224  for(int i = 0; it != end; i++, it++)
225  line[i] = new MLine(model.getMeshVertexByTag(it->first + 1),
226  model.getMeshVertexByTag(it->second + 1));
227 
228  // Add Elements as a Chain in GModel (see Chain::addToModel in src/geo/Chain.h)
229 
230  std::string name = "";
231  int entityNum;
232  int physicalNum;
233  int max[4];
234 
235  // Get entity number
236  for(int i = 0; i < 4; i++) max[i] = model.getMaxElementaryNumber(i);
237  entityNum = *std::max_element(max, max + 4) + 1;
238 
239  // Get physcial number if not specified
240  if(tag < 0) {
241  for(int i = 0; i < 4; i++) max[i] = model.getMaxPhysicalNumber(i);
242  physicalNum = *std::max_element(max, max + 4) + 1;
243  }
244  else {
245  physicalNum = tag;
246  }
247 
248  // Add MLines to new entity
249  std::map<int, std::vector<MElement *> > entityMap;
250  entityMap[entityNum] = line;
251 
252  // Name new physical
253  std::map<int, std::string> physicalInfo;
254  physicalInfo[physicalNum] = name;
255 
256  // Add new physical to new entity
257  std::map<int, std::map<int, std::string> > physicalMap;
258  physicalMap[entityNum] = physicalInfo;
259 
260  // Add in GModel
261  model.storeChain(1, entityMap, physicalMap);
262  model.setPhysicalName(name, 1, physicalNum);
263 }
264 
265 std::pair<int, int>
266 GMSH_SpanningTreePlugin::minmax(const std::pair<int, int> &p)
267 {
268  if(p.first < p.second)
269  return std::pair<int, int>(p.first, p.second);
270  else
271  return std::pair<int, int>(p.second, p.first);
272 }
273 
275 {
276  // All elements are disjoint
277  parent.resize(n);
278  rank.resize(n, 0);
279 
280  for(size_t i = 0; i < n; i++) parent[i] = i;
281 }
282 
284 {
285  parent.clear();
286  rank.clear();
287 }
288 
290 {
291  // Path compression
292  if(parent[a] != a) parent[a] = find(parent[a]);
293 
294  return parent[a];
295 }
296 
298 {
299  // Union by rank
300 
301  // Get roots
302  int aRoot = find(a);
303  int bRoot = find(b);
304 
305  // If not in same set -> unite! Otherwise, nothing to do...
306  if(aRoot != bRoot) {
307  if(rank[aRoot] < rank[bRoot]) // If aRoot is a smaller set
308  std::swap(aRoot, bRoot); // -> Swap: bRoot is always the smaller set
309  parent[bRoot] = aRoot; // Attach smaller set (B) to bigger set (A)
310  if(rank[aRoot] == rank[bRoot]) // If both sets had the same rank
311  rank[aRoot]++; // -> Increase rank of bigger set (A)
312  }
313 }
314 
316 {
317  // Show (node, parent) [using Gmsh's 1-base index]
318  stringstream str;
319  for(size_t i = 0; i < parent.size(); i++)
320  str << "(" << i + 1 << ", " << parent[i] + 1 << ")" << endl;
321 
322  return str.str();
323 }
324 
326  const std::pair<int, int> &a, const std::pair<int, int> &b) const
327 {
328  std::pair<int, int> as = minmax(a);
329  std::pair<int, int> bs = minmax(b);
330 
331  return as < bs;
332 }
GMSH_SpanningTreePlugin::DSU
Definition: SpanningTree.h:19
StringXString
Definition: Options.h:910
SpanningTreeOptions_Number
StringXNumber SpanningTreeOptions_Number[]
Definition: SpanningTree.cpp:17
GMSH_SpanningTreePlugin::DSU::toString
std::string toString()
Definition: SpanningTree.cpp:315
TimeOfDay
double TimeOfDay()
Definition: OS.cpp:399
std::swap
void swap(picojson::value &x, picojson::value &y)
Definition: picojson.h:1136
GModel::getMaxElementaryNumber
int getMaxElementaryNumber(int dim)
Definition: GModel.cpp:817
GModel::getNumMeshVertices
std::size_t getNumMeshVertices(int dim=-1) const
Definition: GModel.cpp:1529
GMSH_Plugin
Definition: Plugin.h:26
SpanningTreeOptions_String
StringXString SpanningTreeOptions_String[]
Definition: SpanningTree.cpp:21
GMSH_SpanningTreePlugin::getOption
StringXNumber * getOption(int iopt)
Definition: SpanningTree.cpp:74
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
OS.h
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
StringXNumber
Definition: Options.h:918
GMSH_SpanningTreePlugin::DSU::join
void join(int a, int b)
Definition: SpanningTree.cpp:297
GModel::getMeshVertexByTag
MVertex * getMeshVertexByTag(int n)
Definition: GModel.cpp:1953
MLine.h
GMSH_SpanningTreePlugin::addToModel
static void addToModel(GModel &model, Tree &tree, int tag)
Definition: SpanningTree.cpp:213
GMSH_SpanningTreePlugin::EdgeSet
std::set< std::pair< int, int >, Sort > EdgeSet
Definition: SpanningTree.h:43
GMSH_SpanningTreePlugin::getNbOptions
int getNbOptions() const
Definition: SpanningTree.cpp:69
GMSH_SpanningTreePlugin::getAllMElement
static void getAllMElement(GModel &model, int physical, int dim, ElementSet &element)
Definition: SpanningTree.cpp:184
GMSH_SpanningTreePlugin::parse
static std::string parse(std::string str, std::list< int > &physical)
Definition: SpanningTree.cpp:160
GMSH_SpanningTreePlugin::ElementSet
std::set< const MElement *, MElementPtrLessThan > ElementSet
Definition: SpanningTree.h:42
minmax
static void minmax(int n, double *X, double *Y, double *Z, double *min, double *max)
Definition: OctreePost.cpp:22
MLine
Definition: MLine.h:21
GMSH_RegisterSpanningTreePlugin
GMSH_Plugin * GMSH_RegisterSpanningTreePlugin()
Definition: SpanningTree.cpp:28
GMSH_SpanningTreePlugin
Definition: SpanningTree.h:17
GMSH_SpanningTreePlugin::GMSH_SpanningTreePlugin
GMSH_SpanningTreePlugin()
Definition: SpanningTree.cpp:34
GMSH_SpanningTreePlugin::getAllMEdge
static void getAllMEdge(ElementSet &element, EdgeSet &edge)
Definition: SpanningTree.cpp:201
GModel::getPhysicalGroups
void getPhysicalGroups(std::map< int, std::vector< GEntity * > > groups[4]) const
Definition: GModel.cpp:837
GMSH_SpanningTreePlugin::DSU::~DSU
~DSU()
Definition: SpanningTree.cpp:283
GModel::getMaxPhysicalNumber
int getMaxPhysicalNumber(int dim)
Definition: GModel.cpp:917
GMSH_SpanningTreePlugin::getHelp
std::string getHelp() const
Definition: SpanningTree.cpp:43
GMSH_FULLRC
#define GMSH_FULLRC
Definition: Options.h:20
GModel
Definition: GModel.h:44
GMSH_SpanningTreePlugin::Tree
std::list< std::pair< int, int > > Tree
Definition: SpanningTree.h:44
Cpu
double Cpu()
Definition: OS.cpp:366
SpanningTree.h
GMSH_SpanningTreePlugin::DSU::find
int find(int a)
Definition: SpanningTree.cpp:289
picojson::parse
std::string parse(value &out, Iter &pos, const Iter &last)
Definition: picojson.h:1058
GMSH_SpanningTreePlugin::minmax
static std::pair< int, int > minmax(const std::pair< int, int > &p)
Definition: SpanningTree.cpp:266
StringXString::def
std::string def
Definition: Options.h:914
element
Definition: shapeFunctions.h:12
GMSH_SpanningTreePlugin::getAuthor
std::string getAuthor() const
Definition: SpanningTree.cpp:67
GMSH_SpanningTreePlugin::DSU::DSU
DSU(size_t n)
Definition: SpanningTree.cpp:274
GMSH_SpanningTreePlugin::getName
std::string getName() const
Definition: SpanningTree.cpp:36
output
static void output(code_int code)
Definition: gl2gif.cpp:743
GMSH_SpanningTreePlugin::spanningTree
static void spanningTree(EdgeSet &edge, DSU &vertex, Tree &tree)
Definition: SpanningTree.cpp:145
std
Definition: picojson.h:1135
GModel::storeChain
void storeChain(int dim, std::map< int, std::vector< MElement * > > &entityMap, std::map< int, std::map< int, std::string > > &physicalMap)
Definition: GModel.cpp:2247
GModel::setPhysicalName
int setPhysicalName(const std::string &name, int dim, int num=0)
Definition: GModel.cpp:937
GMSH_SpanningTreePlugin::run
int run()
Definition: SpanningTree.cpp:89
GMSH_SpanningTreePlugin::getShortHelp
std::string getShortHelp() const
Definition: SpanningTree.cpp:38
GModel.h
GMSH_SpanningTreePlugin::getNbOptionsStr
int getNbOptionsStr() const
Definition: SpanningTree.cpp:79
line
Definition: shapeFunctions.h:342
GMSH_SpanningTreePlugin::Sort::operator()
bool operator()(const std::pair< int, int > &a, const std::pair< int, int > &b) const
Definition: SpanningTree.cpp:325
GMSH_SpanningTreePlugin::getOptionStr
StringXString * getOptionStr(int iopt)
Definition: SpanningTree.cpp:84
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136