gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
Chain.h
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 //
6 // Contributed by Matti Pellikka <matti.pellikka@gmail.com>.
7 
8 #ifndef CHAIN_H
9 #define CHAIN_H
10 
11 #include <sstream>
12 #include "GModel.h"
13 #include "MElement.h"
14 #include "Context.h"
15 
16 #if defined(HAVE_POST)
17 #include "PView.h"
18 #include "PViewOptions.h"
19 #endif
20 
21 #if defined(HAVE_KBIPACK)
22 
23 void updateFltk();
24 std::string convertInt(int number);
25 
26 // Class whose derivative classes are to have partial or total order
27 template <class Type> class PosetCat {
28 public:
29  virtual ~PosetCat() {}
31  virtual bool lessThan(const Type &t2) const = 0;
32 
33  friend bool operator<(const Type &t1, const Type &t2)
34  {
35  return t1.lessThan(t2);
36  }
37  friend bool operator>(const Type &t1, const Type &t2)
38  {
39  return !t1.lessThan(t2);
40  }
41  friend bool operator==(const Type &t1, const Type &t2)
42  {
43  if(t1.lessThan(t2) && t2.lessThan(t1)) return true;
44  return false;
45  }
46  friend bool operator!=(const Type &t1, const Type &t2)
47  {
48  if(t1.lessThan(t2) && t2.lessThan(t1)) return false;
49  return true;
50  }
51  friend bool operator<=(const Type &t1, const Type &t2)
52  {
53  if(t1.lessThan(t2) || t1 == t2) return true;
54  return false;
55  }
56  friend bool operator>=(const Type &t1, const Type &t2)
57  {
58  if(!t1.lessThan(t2) || t1 == t2) return true;
59  return false;
60  }
61 };
62 
63 // Class whose derivative classes are to have vector space structure
64 template <class V, class S> class VectorSpaceCat {
65 public:
66  virtual ~VectorSpaceCat() {}
67 
69  virtual V &operator+=(const V &v) = 0;
70  virtual V &operator*=(const S &s) = 0;
71  // virtual V& zero() = 0;
73 
74  friend V operator+(const V &v1, const V &v2)
75  {
76  V temp(v1);
77  temp += v2;
78  return temp;
79  }
80  friend V operator-(const V &v1, const V &v2)
81  {
82  V temp(v1);
83  temp -= v2;
84  return temp;
85  }
86  friend V operator*(const S &s, const V &v)
87  {
88  V temp(v);
89  temp *= s;
90  return temp;
91  }
92  friend V operator*(const V &v, const S &s) { return s * v; }
93  friend V operator/(const V &v, const S &s)
94  {
95  S invs = 1. / s;
96  return invs * v;
97  }
98 
99  // Warning: assummes that the multiplicative
100  // identity element of field S can be converted from double "1."
101  // and that additive inverse of v in Abelian group V equals v*-1.
102  // (true e.g. for double and std::complex<double>),
103  // otherwise these need to be overridden by the user
104 
105  virtual V &operator-() { return (*this) *= (-1.); }
106  virtual V &operator/=(const S &s)
107  {
108  S temp = 1. / s;
109  return (*this *= temp);
110  }
111  virtual V &operator-=(const V &v)
112  {
113  V temp(v);
114  temp = -temp;
115  return (*this += temp);
116  }
117 };
118 
119 // Class to represent an 'elementary chain', a mesh cell
120 class ElemChain : public PosetCat<ElemChain> {
121 private:
122  char _dim;
123  std::vector<MVertex *> _v;
124  std::vector<char> _si;
125  inline void _sortVertexIndices();
126  bool _equalVertices(const std::vector<MVertex *> &v2) const;
127 
128  static std::map<GEntity *, std::set<MVertex *, MVertexPtrLessThan>,
130  _vertexCache;
131 
132 public:
133  ElemChain(MElement *e);
134  ElemChain(int dim, std::vector<MVertex *> &v);
135 
136  int getDim() const { return _dim; }
137  int getNumVertices() const { return _v.size(); }
138  MVertex *getMeshVertex(int i) const { return _v.at(i); }
139  void getMeshVertices(std::vector<MVertex *> &v) const { v = _v; }
140  int getNumSortedVertices() const { return _v.size(); }
141  inline int getSortedVertex(int i) const;
142 
143  int getTypeMSH() const;
144  MElement *createMeshElement() const;
145 
146  int compareOrientation(const ElemChain &c2) const;
147  bool lessThan(const ElemChain &c2) const;
148 
149  int getNumBoundaryElemChains() const;
150  ElemChain getBoundaryElemChain(int i) const;
151 
152  bool inEntity(GEntity *e) const;
153 
154  static void clearVertexCache() { _vertexCache.clear(); }
155  static int getTypeMSH(int dim, int numVertices);
156  static int getNumBoundaries(int dim, int numVertices);
157  static void getBoundaryVertices(int i, int dim, int numVertices,
158  const std::vector<MVertex *> &v,
159  std::vector<MVertex *> &vertices);
160 };
161 
162 void findEntitiesInPhysicalGroups(GModel *m,
163  const std::vector<int> &physicalGroups,
164  std::vector<GEntity *> &entities);
165 
166 // Class to represent a chain, formal sum of elementary chains
167 template <class C> class Chain : public VectorSpaceCat<Chain<C>, C> {
168 private:
169  // Dimension of the chain
170  int _dim;
171  // Elementary chains and their coefficients in the chain
172  std::map<ElemChain, C> _elemChains;
173  // A name for the chain
174  std::string _name;
175 
176  Chain<C> _getTraceOrProject(const std::vector<GEntity *> &entities,
177  bool trace) const;
178 
179 public:
180  // Elementary chain iterators
181  typedef typename std::map<ElemChain, C>::iterator ecit;
182  typedef typename std::map<ElemChain, C>::const_iterator cecit;
183 
184  // Create zero chain
185  Chain() : _dim(-1), _name("") {}
186 
187  // Create chain from Gmsh model physical group
188  // (all mesh elements in the physical group are treated as
189  // elementary chains with coefficient 1)
190  Chain(GModel *m, int physicalGroup);
191 
192  // Get/set the chain name
193  std::string getName() const { return _name; }
194  void setName(std::string name) { _name = name; }
195 
196  // Get chain dimension
197  int getDim() const { return _dim; }
198 
199  // True if a zero element of a chain space
200  bool isZero() const { return _elemChains.empty(); }
201 
202  // Iterators to elementrary chains in the chain
203  cecit firstElemChain() const { return _elemChains.begin(); }
204  cecit lastElemChain() const { return _elemChains.end(); }
205 
206  // Add mesh element or elementary chain with given coefficient to the chain
207  void addMeshElement(MElement *e, C coeff = 1);
208  void addElemChain(const ElemChain &c, C coeff = 1);
209 
210  // Vector space operations for chains (these two induce the rest)
211  Chain<C> &operator+=(const Chain<C> &chain);
212  Chain<C> &operator*=(const C &coeff);
213 
214  // Get elementary chain coefficient the chain
215  C getCoefficient(const ElemChain &c2) const;
216 
217  // Get mesh element (or its indicated face, edge, or vertex)
218  // coefficient in the chain, interpreted as a elementary chain
219  C getCoefficient(MElement *e, int subElement = -1) const;
220 
221  // Get the boundary chain of this chain
222  Chain<C> getBoundary() const;
223 
224  // Get a chain which contains elementary chains that are
225  // in the given physical group or elementary entities
226  Chain<C> getTrace(GModel *m, int physicalGroup) const;
227  Chain<C> getTrace(GModel *m, const std::vector<int> &physicalGroups) const;
228  Chain<C> getTrace(const std::vector<GEntity *> &entities) const;
229 
230  // Get a chain which contains elementary chains that are *not*
231  // in the given physical group or elementary entities
232  Chain<C> getProject(GModel *m, int physicalGroup) const;
233  Chain<C> getProject(GModel *m, const std::vector<int> &physicalGroups) const;
234  Chain<C> getProject(const std::vector<GEntity *> &entities) const;
235 
236  // The above two methods decompose a chain c so that
237  // (c - c.getTrace(...) - c.getProject(...)).isZero() == true
238  // holds
239 
240  // Add chain to Gmsh model as a physical group,
241  // elementary chains are turned into mesh elements with
242  // orientation and multiplicity given by elementary chain coefficient
243  // (and create a post-processing view)
244  // (and request a physical group number)
245  // returns physical group number of the chain
246  int addToModel(GModel *m, bool post = true,
247  int physicalNumRequest = -1) const;
248 };
249 
250 template <class C> Chain<C>::Chain(GModel *m, int physicalGroup)
251 {
252  _dim = 0;
253  std::vector<int> groups(1, physicalGroup);
254  std::vector<GEntity *> entities;
255  findEntitiesInPhysicalGroups(m, groups, entities);
256 
257  for(std::size_t i = 0; i < entities.size(); i++) {
258  GEntity *e = entities.at(i);
259  _dim = e->dim();
260  for(std::size_t j = 0; j < e->getNumMeshElements(); j++) {
261  this->addMeshElement(e->getMeshElement(j));
262  }
263  this->setName(m->getPhysicalName(this->getDim(), physicalGroup));
264  }
265 }
266 
267 template <class C> C Chain<C>::getCoefficient(const ElemChain &c2) const
268 {
269  cecit it = _elemChains.find(c2);
270  if(it != _elemChains.end())
271  return it->second * c2.compareOrientation(it->first);
272  else
273  return 0;
274 }
275 
276 template <class C> C Chain<C>::getCoefficient(MElement *e, int subElement) const
277 {
278  if(this->getDim() == e->getDim()) {
279  ElemChain ec(e);
280  return this->getCoefficient(ec);
281  }
282  if(subElement == -1) return 0;
283  std::vector<MVertex *> v;
284  if(this->getDim() == 0) {
285  if(subElement >= e->getNumVertices()) return 0;
286  v = std::vector<MVertex *>(1, e->getVertex(subElement));
287  }
288  else if(this->getDim() == 1) {
289  if(subElement >= e->getNumEdges()) return 0;
290  e->getEdgeVertices(subElement, v);
291  v.resize(2);
292  }
293  else if(this->getDim() == 2) {
294  if(subElement >= e->getNumFaces()) return 0;
295  e->getFaceVertices(subElement, v);
296  if(e->getType() == TYPE_TET ||
297  (e->getType() == TYPE_PRI && subElement < 4) ||
298  (e->getType() == TYPE_PYR && subElement < 2))
299  v.resize(3);
300  else
301  v.resize(4);
302  }
303  ElemChain ec(this->getDim(), v);
304  return this->getCoefficient(ec);
305 }
306 
307 template <class C> C incidence(const Chain<C> &c1, const Chain<C> &c2)
308 {
309  C incidence = 0;
310  if(c1.getDim() != c2.getDim()) return incidence;
311  for(typename Chain<C>::cecit it = c1.firstElemChain();
312  it != c1.lastElemChain(); it++) {
313  incidence += it->second * c2.getCoefficient(it->first);
314  }
315  if(incidence != 0) {
316  Msg::Debug("%d-chains \'%s\' and \'%s\' have incidence %d", c1.getDim(),
317  c1.getName().c_str(), c2.getName().c_str(), incidence);
318  }
319  return incidence;
320 }
321 
322 template <class C> Chain<C> boundary(const ElemChain &c)
323 {
324  Chain<C> result;
325  for(int i = 0; i < c.getNumBoundaryElemChains(); i++) {
326  C coeff = 1;
327  if(c.getDim() == 1 && i == 0) coeff = -1;
328  result.addElemChain(c.getBoundaryElemChain(i), coeff);
329  }
330  return result;
331 }
332 
333 template <class C> Chain<C> Chain<C>::getBoundary() const
334 {
335  Chain<C> result;
336  for(cecit it = _elemChains.begin(); it != _elemChains.end(); it++) {
337  C coeff = it->second;
338  result += boundary<C>(it->first) * coeff;
339  }
340  if(result.isZero())
341  Msg::Info("The boundary chain is zero element in C%d", result.getDim());
342  return result;
343 }
344 
345 template <class C>
346 Chain<C> Chain<C>::getTrace(GModel *m, int physicalGroup) const
347 {
348  std::vector<int> groups(1, physicalGroup);
349  return this->getTrace(m, groups);
350 }
351 
352 template <class C>
353 Chain<C> Chain<C>::getProject(GModel *m, int physicalGroup) const
354 {
355  std::vector<int> groups(1, physicalGroup);
356  return this->getProject(m, groups);
357 }
358 
359 template <class C>
360 Chain<C> Chain<C>::getTrace(GModel *m,
361  const std::vector<int> &physicalGroups) const
362 {
363  std::vector<GEntity *> entities;
364  findEntitiesInPhysicalGroups(m, physicalGroups, entities);
365  if(entities.empty()) return Chain<C>();
366  return this->_getTraceOrProject(entities, true);
367 }
368 
369 template <class C>
370 Chain<C> Chain<C>::getProject(GModel *m,
371  const std::vector<int> &physicalGroups) const
372 {
373  std::vector<GEntity *> entities;
374  findEntitiesInPhysicalGroups(m, physicalGroups, entities);
375  if(entities.empty()) return Chain<C>();
376  return this->_getTraceOrProject(entities, false);
377 }
378 
379 template <class C>
380 Chain<C> Chain<C>::_getTraceOrProject(const std::vector<GEntity *> &entities,
381  bool trace) const
382 {
383  Chain<C> result;
384  for(cecit it = _elemChains.begin(); it != _elemChains.end(); it++) {
385  bool inDomain = false;
386  for(std::size_t i = 0; i < entities.size(); i++) {
387  if(it->first.inEntity(entities.at(i))) {
388  inDomain = true;
389  break;
390  }
391  }
392  if(inDomain && trace) result.addElemChain(it->first, it->second);
393  if(!inDomain && !trace) result.addElemChain(it->first, it->second);
394  }
395  return result;
396 }
397 
398 template <class C>
399 Chain<C> Chain<C>::getTrace(const std::vector<GEntity *> &entities) const
400 {
401  return this->_getTraceOrProject(entities, true);
402 }
403 
404 template <class C>
405 Chain<C> Chain<C>::getProject(const std::vector<GEntity *> &entities) const
406 {
407  return this->_getTraceOrProject(entities, false);
408 }
409 
410 template <class C> void Chain<C>::addMeshElement(MElement *e, C coeff)
411 {
412  ElemChain ce(e);
413  this->addElemChain(ce, coeff);
414 }
415 
416 template <class C> void Chain<C>::addElemChain(const ElemChain &c, C coeff)
417 {
418  if(coeff == 0) return;
419  if(_dim != -1 && _dim != c.getDim()) {
420  Msg::Error("Cannot add elementrary %d-chain to %d-chain", c.getDim(), _dim);
421  return;
422  }
423  if(_dim == -1) _dim = c.getDim();
424  std::pair<ecit, bool> ii = _elemChains.insert(std::make_pair(c, coeff));
425  if(!ii.second) {
426  ii.first->second += coeff * c.compareOrientation(ii.first->first);
427  if(ii.first->second == 0) _elemChains.erase(ii.first);
428  }
429 }
430 
431 template <class C> Chain<C> &Chain<C>::operator+=(const Chain<C> &chain)
432 {
433  for(cecit it = chain.firstElemChain(); it != chain.lastElemChain(); it++)
434  this->addElemChain(it->first, it->second);
435  return *this;
436 }
437 
438 template <class C> Chain<C> &Chain<C>::operator*=(const C &coeff)
439 {
440  if(coeff == 0)
441  _elemChains.clear();
442  else
443  for(ecit it = _elemChains.begin(); it != _elemChains.end(); it++)
444  it->second *= coeff;
445  return *this;
446 }
447 
448 template <class C>
449 int Chain<C>::addToModel(GModel *m, bool post, int physicalNumRequest) const
450 {
451  if(this->isZero()) {
452  Msg::Info("A chain is zero element of C%d, not added to the model",
453  this->getDim());
454  return -1;
455  }
456 
457  std::string name = _name;
458  // avoid too long names, which screw up the GUI and the msh file
459  if(name.size() > 128) name.resize(128);
460 
461  std::vector<MElement *> elements;
462  std::map<int, std::vector<double> > data;
463  int dim = this->getDim();
464 
465  for(cecit it = this->firstElemChain(); it != this->lastElemChain(); it++) {
466  MElement *e = it->first.createMeshElement();
467  C coeff = it->second;
468  elements.push_back(e);
469  if(dim > 0 && coeff < 0) e->reverse();
470 
471  // if elementary chain coefficient is other than -1 or 1,
472  // add multiple identical MElements to the physical group
473  for(int i = 1; i < abs(coeff); i++) {
474  MElement *ecopy = it->first.createMeshElement();
475  if(dim > 0 && coeff < 0) ecopy->reverse();
476  elements.push_back(ecopy);
477  }
478  if(dim > 0) coeff = abs(coeff);
479 
480  std::vector<double> coeffs(1, coeff);
481  data[e->getNum()] = coeffs;
482  }
483  int max[4];
484  for(int i = 0; i < 4; i++) max[i] = m->getMaxElementaryNumber(i);
485  int entityNum = *std::max_element(max, max + 4) + 1;
486  for(int i = 0; i < 4; i++) max[i] = m->getMaxPhysicalNumber(i);
487  int physicalNum = *std::max_element(max, max + 4) + 1;
488  if(physicalNumRequest > -1 && physicalNumRequest < physicalNum)
489  Msg::Warning("Requested chain physical group number already taken. Using "
490  "next available.");
491  else if(physicalNumRequest > -1 && physicalNumRequest >= physicalNum)
492  physicalNum = physicalNumRequest;
493 
494  std::map<int, std::vector<MElement *> > entityMap;
495  entityMap[entityNum] = elements;
496  std::map<int, std::map<int, std::string> > physicalMap;
497  std::map<int, std::string> physicalInfo;
498  physicalInfo[physicalNum] = name;
499  physicalMap[entityNum] = physicalInfo;
500  m->storeChain(dim, entityMap, physicalMap);
501  m->setPhysicalName(name, dim, physicalNum);
502 
503 #if defined(HAVE_POST)
504  if(post && CTX::instance()->batch == 0) {
505  // create PView for instant visualization
506  std::string pnum = convertInt(physicalNum);
507  std::string postname = pnum + "=" + name;
508  PView *view = new PView(postname, "ElementData", m, data, 0., 1);
509  // the user should be interested about the orientations
510  int size = 30;
511  PViewOptions *opt = view->getOptions();
512  opt->visible = 0;
513  if(opt->tangents == 0) opt->tangents = size;
514  if(opt->normals == 0) opt->normals = size;
515  updateFltk();
516  }
517 #endif
518 
519  return physicalNum;
520 }
521 
522 #endif
523 
524 #endif
MElement::getNum
virtual std::size_t getNum() const
Definition: MElement.h:68
operator+
SPoint2 operator+(const SPoint2 &a, const SPoint2 &b)
Definition: SPoint2.h:58
PViewOptions::tangents
double tangents
Definition: PViewOptions.h:53
operator*
SVector3 operator*(const STensor3 &t, const SVector3 &v)
Definition: STensor3.h:303
PView
Definition: PView.h:27
GModel::getMaxElementaryNumber
int getMaxElementaryNumber(int dim)
Definition: GModel.cpp:817
robin_hood::operator>
constexpr bool operator>(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:680
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
MElement::getFaceVertices
virtual void getFaceVertices(const int num, std::vector< MVertex * > &v) const
Definition: MElement.h:225
Msg::Debug
static void Debug(const char *fmt,...)
Definition: GmshMessage.cpp:752
c
static double c(int i, int j, fullMatrix< double > &CA, const std::vector< SPoint3 > &P, const std::vector< SPoint3 > &Q)
Definition: discreteFrechetDistance.cpp:15
MVertex
Definition: MVertex.h:24
MElement::getDim
virtual int getDim() const =0
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
robin_hood::operator<
constexpr bool operator<(pair< A, B > const &x, pair< A, B > const &y) noexcept(noexcept(std::declval< A const & >()< std::declval< A const & >()) &&noexcept(std::declval< B const & >()< std::declval< B const & >()))
Definition: robin_hood.h:674
PView.h
operator-
SPoint2 operator-(const SPoint2 &a, const SPoint2 &b)
Definition: SPoint2.h:63
MElement::getEdgeVertices
virtual void getEdgeVertices(const int num, std::vector< MVertex * > &v) const
Definition: MElement.h:221
robin_hood::operator>=
constexpr bool operator>=(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:688
GEntity
Definition: GEntity.h:31
GEntityPtrLessThan
Definition: GEntity.h:419
TYPE_PRI
#define TYPE_PRI
Definition: GmshDefines.h:70
MElement::getNumVertices
virtual std::size_t getNumVertices() const =0
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
robin_hood::operator<=
constexpr bool operator<=(pair< A, B > const &x, pair< A, B > const &y)
Definition: robin_hood.h:684
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
GModel::getPhysicalName
std::string getPhysicalName(int dim, int num) const
Definition: GModel.cpp:961
MElement::getType
virtual int getType() const =0
MElement::getNumFaces
virtual int getNumFaces()=0
GEntity::getNumMeshElements
virtual std::size_t getNumMeshElements() const
Definition: GEntity.h:348
GModel::getMaxPhysicalNumber
int getMaxPhysicalNumber(int dim)
Definition: GModel.cpp:917
GModel
Definition: GModel.h:44
PViewOptions.h
MElement::reverse
virtual void reverse()
Definition: MElement.h:308
MElement
Definition: MElement.h:30
getBoundary
static int getBoundary(int type, const int(**boundary)[6][4])
Definition: Skin.cpp:165
S
#define S
Definition: DefaultOptions.h:21
TYPE_PYR
#define TYPE_PYR
Definition: GmshDefines.h:69
PViewOptions::normals
double normals
Definition: PViewOptions.h:53
Context.h
GEntity::getMeshElement
virtual MElement * getMeshElement(std::size_t index) const
Definition: GEntity.h:363
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
MElement.h
picojson::operator!=
bool operator!=(const value &x, const value &y)
Definition: picojson.h:1129
PViewOptions
Definition: PViewOptions.h:16
picojson::operator==
bool operator==(const value &x, const value &y)
Definition: picojson.h:1110
PView::getOptions
PViewOptions * getOptions()
Definition: PView.h:81
getMeshVertices
static bool getMeshVertices(GModel *m, int num, int *n, std::vector< MVertex * > &vec)
Definition: GModelIO_ACTRAN.cpp:17
GModel::setPhysicalName
int setPhysicalName(const std::string &name, int dim, int num=0)
Definition: GModel.cpp:937
TYPE_TET
#define TYPE_TET
Definition: GmshDefines.h:68
GModel.h
ElementType::getNumVertices
int getNumVertices(int type)
Definition: ElementType.cpp:456
GEntity::dim
virtual int dim() const
Definition: GEntity.h:196
MElement::getNumEdges
virtual int getNumEdges() const =0
c1
const double c1
Definition: GaussQuadratureHex.cpp:16
PViewOptions::visible
int visible
Definition: PViewOptions.h:54