gmsh-TingyuanDoc  0.1
An Open-Source Timing-driven Analytical Mixed-size FPGA Placer
Crack.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 
6 #include "Crack.h"
7 #include "GModel.h"
8 #include "discreteEdge.h"
9 #include "discreteFace.h"
10 #include "MElement.h"
11 #include "MLine.h"
12 #include "MTriangle.h"
13 #include "MQuadrangle.h"
14 #include "MEdge.h"
15 #include "Context.h"
16 
18  {GMSH_FULLRC, "Dimension", nullptr, 1.},
19  {GMSH_FULLRC, "PhysicalGroup", nullptr, 1.},
20  {GMSH_FULLRC, "OpenBoundaryPhysicalGroup", nullptr, 0.},
21  {GMSH_FULLRC, "AuxiliaryPhysicalGroup", nullptr, 0},
22  {GMSH_FULLRC, "NormalX", nullptr, 0.},
23  {GMSH_FULLRC, "NormalY", nullptr, 0.},
24  {GMSH_FULLRC, "NormalZ", nullptr, 1.},
25  {GMSH_FULLRC, "NewPhysicalGroup", nullptr, 0},
26  {GMSH_FULLRC, "DebugView", nullptr, 0}
27 };
28 
29 extern "C" {
31 }
32 
33 std::string GMSH_CrackPlugin::getHelp() const
34 {
35  return "Plugin(Crack) creates a crack around the physical "
36  "group `PhysicalGroup' of dimension `Dimension' (1 or 2), "
37  "embedded in a mesh of dimension `Dimension' + 1. "
38  "The plugin duplicates the nodes and the elements on "
39  "the crack and stores them in a new discrete curve "
40  "(`Dimension' = 1) or surface (`Dimension' = 2). The "
41  "elements touching the crack on the positive side "
42  "are modified to use the newly generated nodes."
43  "If `OpenBoundaryPhysicalGroup' is given (> 0), its "
44  "nodes are duplicated and the crack will be left "
45  "open on that (part of the) boundary. Otherwise, the "
46  "lips of the crack are sealed, i.e., its nodes are "
47  "not duplicated. If `AuxiliaryPhysicalGroup' is given "
48  "(> 0), its elements are considered in addition to those in "
49  "`PhysicalGroup' for the logic that groups the elements "
50  "into the positive and negative side of the crack. "
51  "However, the nodes in `AuxiliaryPhysicalGroup' are not "
52  "duplicated (unless they are also in `PhysicalGroup'). "
53  "This can be useful to treat corner cases in non-trivial "
54  "geometries. For 1D cracks, `NormalX', `NormalY' and "
55  "`NormalZ' provide the reference normal of the surface "
56  "in which the crack is supposed to be embedded. If "
57  "`NewPhysicalGroup' is positive, use it as the tag of "
58  "the newly created curve or surface; otherwise use "
59  "`PhysicalGroup'.";
60 }
61 
63 {
64  return sizeof(CrackOptions_Number) / sizeof(StringXNumber);
65 }
66 
68 {
69  return &CrackOptions_Number[iopt];
70 }
71 
72 class EdgeData {
73 public:
74  EdgeData(MEdge e) : edge(e) {}
76  std::vector<MVertex *> data;
77 };
78 
80  : public std::binary_function<EdgeData, EdgeData, bool> {
81  bool operator()(const EdgeData &e1, const EdgeData &e2) const
82  {
83  if(e1.edge.getMinVertex() < e2.edge.getMinVertex()) return true;
84  if(e1.edge.getMinVertex() > e2.edge.getMinVertex()) return false;
85  if(e1.edge.getMaxVertex() < e2.edge.getMaxVertex()) return true;
86  return false;
87  }
88 };
89 
91 {
92  int dim = (int)CrackOptions_Number[0].def;
93  int physical = (int)CrackOptions_Number[1].def;
94  int open = (int)CrackOptions_Number[2].def;
95  int aux = (int)CrackOptions_Number[3].def;
96  SVector3 normal1d(CrackOptions_Number[4].def, CrackOptions_Number[5].def,
97  CrackOptions_Number[6].def);
98  int newPhysical = (int)CrackOptions_Number[7].def;
99  int debug = (int)CrackOptions_Number[8].def;
100 
101  if(dim != 1 && dim != 2) {
102  Msg::Error("Crack dimension should be 1 or 2");
103  return view;
104  }
105 
106  GModel *m = GModel::current();
107  std::map<int, std::vector<GEntity *> > groups[4];
108  m->getPhysicalGroups(groups);
109  std::vector<GEntity *> entities = groups[dim][physical];
110 
111  if(entities.empty()) {
112  Msg::Error("Physical group %d (dimension %d) is empty", physical, dim);
113  return view;
114  }
115 
116  std::vector<GEntity *> openEntities;
117  if(open > 0) {
118  openEntities = groups[dim - 1][open];
119  if(openEntities.empty()) {
120  Msg::Error("Open boundary physical group %d (dimension %d) is empty",
121  open, dim - 1);
122  return view;
123  }
124  }
125 
126  std::vector<GEntity *> auxEntities;
127  if(aux > 0) {
128  auxEntities = groups[dim][aux];
129  if(auxEntities.empty()) {
130  Msg::Warning("Auxiliary physical group %d (dimension %d) is empty",
131  aux, dim);
132  return view;
133  }
134  }
135 
136  std::set<GEntity *> crackEntities;
137  crackEntities.insert(entities.begin(), entities.end());
138  crackEntities.insert(openEntities.begin(), openEntities.end());
139 
140  // get crack elements
141  std::vector<MElement *> crackElements;
142  for(std::size_t i = 0; i < entities.size(); i++)
143  for(std::size_t j = 0; j < entities[i]->getNumMeshElements(); j++)
144  crackElements.push_back(entities[i]->getMeshElement(j));
145 
146  // get internal crack nodes (and list of connected crack elements), as well as
147  // and boundary nodes
148  std::map<MVertex *, std::vector<MElement *> > crackVertices;
149  std::set<MVertex *> bndVertices;
150  if(dim == 1) {
151  for(std::size_t i = 0; i < crackElements.size(); i++) {
152  for(std::size_t j = 0; j < crackElements[i]->getNumVertices(); j++) {
153  MVertex *v = crackElements[i]->getVertex(j);
154  auto it = crackVertices.find(v);
155  if(it == crackVertices.end())
156  crackVertices[v] = {crackElements[i]};
157  else
158  it->second.push_back(crackElements[i]);
159  }
160  for(std::size_t j = 0; j < crackElements[i]->getNumPrimaryVertices();
161  j++) {
162  MVertex *v = crackElements[i]->getVertex(j);
163  if(bndVertices.find(v) == bndVertices.end())
164  bndVertices.insert(v);
165  else
166  bndVertices.erase(v);
167  }
168  }
169  }
170  else {
171  std::set<EdgeData, MEdgeDataLessThan> bnd;
172  for(std::size_t i = 0; i < crackElements.size(); i++) {
173  for(std::size_t j = 0; j < crackElements[i]->getNumVertices(); j++) {
174  MVertex *v = crackElements[i]->getVertex(j);
175  auto it = crackVertices.find(v);
176  if(it == crackVertices.end())
177  crackVertices[v] = {crackElements[i]};
178  else
179  it->second.push_back(crackElements[i]);
180  }
181  for(int j = 0; j < crackElements[i]->getNumEdges(); j++) {
182  EdgeData ed(crackElements[i]->getEdge(j));
183  if(bnd.find(ed) == bnd.end()) {
184  crackElements[i]->getEdgeVertices(j, ed.data);
185  bnd.insert(ed);
186  }
187  else
188  bnd.erase(ed);
189  }
190  }
191  for(auto it = bnd.begin(); it != bnd.end(); it++)
192  bndVertices.insert(it->data.begin(), it->data.end());
193  }
194 
195  // compute the boundary nodes (if any) of the "OpenBoundary" physical group if
196  // it's a curve
197  std::set<MVertex *> bndVerticesFromOpenBoundary;
198  for(std::size_t i = 0; i < openEntities.size(); i++) {
199  if(openEntities[i]->dim() < 1) continue;
200  for(std::size_t j = 0; j < openEntities[i]->getNumMeshElements(); j++) {
201  MElement *e = openEntities[i]->getMeshElement(j);
202  for(std::size_t k = 0; k < e->getNumPrimaryVertices(); k++) {
203  MVertex *v = e->getVertex(k);
204  if(bndVerticesFromOpenBoundary.find(v) ==
205  bndVerticesFromOpenBoundary.end())
206  bndVerticesFromOpenBoundary.insert(v);
207  else
208  bndVerticesFromOpenBoundary.erase(v);
209  }
210  }
211  }
212 
213  if(bndVerticesFromOpenBoundary.size())
214  Msg::Info("%u nodes on boundary of OpenBoundaryPhysicalGroup",
215  bndVerticesFromOpenBoundary.size());
216 
217  // get open boundary nodes and remove them from boundary nodes (if they are
218  // not on the "boundary of the open boundary" ;-)
219  for(std::size_t i = 0; i < openEntities.size(); i++) {
220  for(std::size_t j = 0; j < openEntities[i]->getNumMeshElements(); j++) {
221  MElement *e = openEntities[i]->getMeshElement(j);
222  for(std::size_t k = 0; k < e->getNumVertices(); k++) {
223  MVertex *v = e->getVertex(k);
224  if(bndVerticesFromOpenBoundary.find(v) ==
225  bndVerticesFromOpenBoundary.end())
226  bndVertices.erase(v);
227  }
228  }
229  }
230  for(auto it = bndVertices.begin(); it != bndVertices.end(); it++)
231  crackVertices.erase(*it);
232 
233  // get auxiliary elements
234  std::vector<MElement *> auxElements;
235  for(std::size_t i = 0; i < auxEntities.size(); i++)
236  for(std::size_t j = 0; j < auxEntities[i]->getNumMeshElements(); j++)
237  auxElements.push_back(auxEntities[i]->getMeshElement(j));
238 
239  // add auxiliary elements to crackVertices if they are connected to the
240  // vertex (see #1750)
241  for(std::size_t i = 0; i < auxElements.size(); i++) {
242  for(std::size_t j = 0; j < auxElements[i]->getNumVertices(); j++) {
243  MVertex *v = auxElements[i]->getVertex(j);
244  auto it = crackVertices.find(v);
245  // vertex v is in crackVertices: add aux element to vector of connected
246  // elements
247  if(it != crackVertices.end())
248  it->second.push_back(auxElements[i]);
249  }
250  }
251 
252  // compute elements on the positive side of the crack, and keep track of each
253  // node in the element that leads to categorizing the element on this side
254  // (this allows to handle the degenerate case where the same element touches
255  // the same crack on both sides, with different nodes - cf. #1750)
256  std::map<MElement *, std::vector<std::size_t> > oneside;
257  std::vector<GEntity *> allentities;
258  m->getEntities(allentities);
259  for(std::size_t ent = 0; ent < allentities.size(); ent++) {
260  if(crackEntities.find(allentities[ent]) != crackEntities.end()) continue;
261  for(std::size_t i = 0; i < allentities[ent]->getNumMeshElements(); i++) {
262  MElement *e = allentities[ent]->getMeshElement(i);
263  for(std::size_t j = 0; j < e->getNumVertices(); j++) {
264  auto it = crackVertices.find(e->getVertex(j));
265  if(it == crackVertices.end()) continue;
266  // the element touches the crack by at least one node: determine if the
267  // vector joining its barycenter to the barycenter of one of the
268  // connected crack elements is not in the same direction as the normal
269  // to the crack element; if the condition is fulfilled for one of the
270  // connected crack elements, we consider the element lies on the
271  // "positive side" of the crack
272  SPoint3 b = e->barycenter();
273  for(auto ce : it->second) {
274  SVector3 dv = SVector3(b, ce->barycenter());
275  SVector3 n;
276  if(dim == 1)
277  n = crossprod(normal1d, ce->getEdge(0).tangent());
278  else
279  n = ce->getFace(0).normal();
280  if(dot(n, dv) < 0) {
281  auto it2 = oneside.find(e);
282  if(it2 == oneside.end())
283  oneside[e] = {j};
284  else {
285  if(std::find(it2->second.begin(), it2->second.end(), j) ==
286  it2->second.end())
287  it2->second.push_back(j);
288  }
289  }
290  }
291  }
292  }
293  }
294 
295  // create new crack entity
296 
297  // TODO: the new discrete entities do not have a consistent topology: we don't
298  // specify their bounding points/curves
299  // a) This is easy to fix if there's no OpenBoundaryPhysicalGroup and
300  // we crack a *single* elementary entity
301  // b) If there is an open boundary, we need to create a new elementary
302  // entity on the boundary, and correctly classify the nodes on it...
303  // and we also need to create boundary elements
304  // c) If we crack a group made of multiple elementary entities we might
305  // want to create multiple cracked entities, and do the same as (b)
306  // for all internal seams
307  //
308  // In practice, c) is not crucial - the current approach simply creates a
309  // single new surface/curve, which is probably fine as in solvers we won't use
310  // the internal seams.
311 
312  GEdge *crackEdge = nullptr;
313  GFace *crackFace = nullptr;
314  if(dim == 1) {
315  crackEdge =
316  new discreteEdge(m, m->getMaxElementaryNumber(1) + 1, nullptr, nullptr);
317  m->add(crackEdge);
318  }
319  else {
320  crackFace = new discreteFace(m, m->getMaxElementaryNumber(2) + 1);
321  m->add(crackFace);
322  }
323  GEntity *crackEntity =
324  crackEdge ? (GEntity *)crackEdge : (GEntity *)crackFace;
325  crackEntity->physicals.push_back(newPhysical ? newPhysical : physical);
326 
327  // duplicate internal crack nodes
328  std::map<MVertex *, MVertex *> vxv;
329  for(auto it = crackVertices.begin(); it != crackVertices.end(); it++) {
330  MVertex *v = it->first;
331  MVertex *newv = new MVertex(v->x(), v->y(), v->z(), crackEntity);
332  crackEntity->mesh_vertices.push_back(newv);
333  vxv[v] = newv;
334  }
335 
336  // duplicate crack elements
337  for(std::size_t i = 0; i < crackElements.size(); i++) {
338  MElement *e = crackElements[i];
339  std::vector<MVertex *> verts;
340  e->getVertices(verts);
341  for(std::size_t j = 0; j < verts.size(); j++) {
342  if(vxv.count(verts[j])) verts[j] = vxv[verts[j]];
343  }
345  MElement *newe = f.create(e->getTypeForMSH(), verts, 0, e->getPartition());
346  if(crackEdge && newe->getType() == TYPE_LIN)
347  crackEdge->lines.push_back((MLine *)newe);
348  else if(crackFace && newe->getType() == TYPE_TRI)
349  crackFace->triangles.push_back((MTriangle *)newe);
350  else if(crackFace && newe->getType() == TYPE_QUA)
351  crackFace->quadrangles.push_back((MQuadrangle *)newe);
352  }
353 
354  // replace vertices in elements on one side of the crack
355  for(auto it = oneside.begin(); it != oneside.end(); it++) {
356  MElement *e = it->first;
357  for(auto i : it->second) {
358  MVertex *v = e->getVertex(i);
359  if(vxv.count(v))
360  e->setVertex(i, vxv[v]);
361  else
362  Msg::Warning("Mesh node %lu not found in cracked nodes", v->getNum());
363  }
364  }
365 
366  if(debug) {
367  std::map<int, std::vector<double> > d;
368  for(auto e : oneside) {
369  // 1: if node duplicated, 0: if node not duplicated
370  std::vector<double> nodeDuplicated(e.first->getNumVertices(), 0.0);
371  for(auto & node: e.second) nodeDuplicated[node] = 1.0;
372  d[e.first->getNum()] = nodeDuplicated;
373  }
374  view = new PView("Positive-side elements and duplicated nodes (1: true, 0: false)",
375  "ElementNodeData", GModel::current(), d, 0, 1);
376  }
377 
379 
380  return view;
381 }
GMSH_CrackPlugin
Definition: Crack.h:15
crossprod
SVector3 crossprod(const SVector3 &a, const SVector3 &b)
Definition: SVector3.h:150
MTriangle.h
PView
Definition: PView.h:27
GMSH_CrackPlugin::getNbOptions
int getNbOptions() const
Definition: Crack.cpp:62
MEdge
Definition: MEdge.h:14
dot
double dot(const SVector3 &a, const SMetric3 &m, const SVector3 &b)
Definition: STensor3.h:71
GModel::getMaxElementaryNumber
int getMaxElementaryNumber(int dim)
Definition: GModel.cpp:817
TYPE_LIN
#define TYPE_LIN
Definition: GmshDefines.h:65
GFace
Definition: GFace.h:33
MElement::getTypeForMSH
virtual int getTypeForMSH() const
Definition: MElement.h:488
GFace::triangles
std::vector< MTriangle * > triangles
Definition: GFace.h:428
GMSH_Plugin
Definition: Plugin.h:26
GMSH_CrackPlugin::getOption
StringXNumber * getOption(int iopt)
Definition: Crack.cpp:67
Msg::Info
static void Info(const char *fmt,...)
Definition: GmshMessage.cpp:587
MEdge::getMaxVertex
MVertex * getMaxVertex() const
Definition: MEdge.h:42
GEdge::lines
std::vector< MLine * > lines
Definition: GEdge.h:42
MElementFactory
Definition: MElement.h:517
discreteEdge
Definition: discreteEdge.h:12
MVertex
Definition: MVertex.h:24
Msg::Warning
static void Warning(const char *fmt,...)
Definition: GmshMessage.cpp:543
Msg::Error
static void Error(const char *fmt,...)
Definition: GmshMessage.cpp:482
MVertex::z
double z() const
Definition: MVertex.h:62
GEntity::physicals
std::vector< int > physicals
Definition: GEntity.h:65
SPoint3
Definition: SPoint3.h:14
LegendrePolynomials::f
void f(int n, double u, double *val)
Definition: orthogonalBasis.cpp:77
StringXNumber
Definition: Options.h:918
SVector3
Definition: SVector3.h:16
TYPE_TRI
#define TYPE_TRI
Definition: GmshDefines.h:66
Crack.h
MLine.h
EdgeData::data
std::vector< MVertex * > data
Definition: Crack.cpp:76
GEntity
Definition: GEntity.h:31
MElement::getNumVertices
virtual std::size_t getNumVertices() const =0
MElement::setVertex
virtual void setVertex(int num, MVertex *v)
Definition: MElement.h:109
GFace::quadrangles
std::vector< MQuadrangle * > quadrangles
Definition: GFace.h:429
GMSH_CrackPlugin::getHelp
std::string getHelp() const
Definition: Crack.cpp:33
MLine
Definition: MLine.h:21
CTX::instance
static CTX * instance()
Definition: Context.cpp:122
MElement::getVertex
virtual const MVertex * getVertex(int num) const =0
GModel::getPhysicalGroups
void getPhysicalGroups(std::map< int, std::vector< GEntity * > > groups[4]) const
Definition: GModel.cpp:837
GEntity::mesh_vertices
std::vector< MVertex * > mesh_vertices
Definition: GEntity.h:56
MElement::getType
virtual int getType() const =0
GMSH_FULLRC
#define GMSH_FULLRC
Definition: Options.h:20
GModel
Definition: GModel.h:44
MEdge::getMinVertex
MVertex * getMinVertex() const
Definition: MEdge.h:41
EdgeData
Definition: Crack.cpp:72
GModel::add
bool add(GRegion *r)
Definition: GModel.h:394
CTX::mesh
contextMeshOptions mesh
Definition: Context.h:313
MElement
Definition: MElement.h:30
discreteFace.h
MLine::getType
virtual int getType() const
Definition: MLine.h:75
MTriangle::getType
virtual int getType() const
Definition: MTriangle.h:106
GModel::getEntities
void getEntities(std::vector< GEntity * > &entities, int dim=-1) const
Definition: GModel.cpp:651
MEdgeDataLessThan
Definition: Crack.cpp:80
MTriangle
Definition: MTriangle.h:26
contextMeshOptions::changed
int changed
Definition: Context.h:82
MElement::getVertices
void getVertices(std::vector< MVertex * > &verts)
Definition: MElement.h:103
TYPE_QUA
#define TYPE_QUA
Definition: GmshDefines.h:67
EdgeData::EdgeData
EdgeData(MEdge e)
Definition: Crack.cpp:74
MEdge.h
discreteEdge.h
ENT_ALL
#define ENT_ALL
Definition: GmshDefines.h:235
Context.h
MQuadrangle.h
MElement::getNumPrimaryVertices
std::size_t getNumPrimaryVertices() const
Definition: MElement.h:160
MElement.h
GEdge
Definition: GEdge.h:26
CrackOptions_Number
StringXNumber CrackOptions_Number[]
Definition: Crack.cpp:17
MElement::barycenter
virtual SPoint3 barycenter(bool primary=false) const
Definition: MElement.cpp:520
MEdgeDataLessThan::operator()
bool operator()(const EdgeData &e1, const EdgeData &e2) const
Definition: Crack.cpp:81
GModel.h
MVertex::y
double y() const
Definition: MVertex.h:61
GMSH_CrackPlugin::execute
PView * execute(PView *)
Definition: Crack.cpp:90
EdgeData::edge
MEdge edge
Definition: Crack.cpp:75
MElement::getPartition
virtual int getPartition() const
Definition: MElement.h:92
MQuadrangle
Definition: MQuadrangle.h:26
GMSH_RegisterCrackPlugin
GMSH_Plugin * GMSH_RegisterCrackPlugin()
Definition: Crack.cpp:30
GModel::current
static GModel * current(int index=-1)
Definition: GModel.cpp:136
MVertex::x
double x() const
Definition: MVertex.h:60
discreteFace
Definition: discreteFace.h:18