20 {
GMSH_FULLRC,
"OpenBoundaryPhysicalGroup",
nullptr, 0.},
21 {
GMSH_FULLRC,
"AuxiliaryPhysicalGroup",
nullptr, 0},
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 "
76 std::vector<MVertex *>
data;
80 :
public std::binary_function<EdgeData, EdgeData, bool> {
101 if(dim != 1 && dim != 2) {
102 Msg::Error(
"Crack dimension should be 1 or 2");
107 std::map<int, std::vector<GEntity *> > groups[4];
109 std::vector<GEntity *> entities = groups[dim][physical];
111 if(entities.empty()) {
112 Msg::Error(
"Physical group %d (dimension %d) is empty", physical, dim);
116 std::vector<GEntity *> openEntities;
118 openEntities = groups[dim - 1][open];
119 if(openEntities.empty()) {
120 Msg::Error(
"Open boundary physical group %d (dimension %d) is empty",
126 std::vector<GEntity *> auxEntities;
128 auxEntities = groups[dim][aux];
129 if(auxEntities.empty()) {
130 Msg::Warning(
"Auxiliary physical group %d (dimension %d) is empty",
136 std::set<GEntity *> crackEntities;
137 crackEntities.insert(entities.begin(), entities.end());
138 crackEntities.insert(openEntities.begin(), openEntities.end());
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));
148 std::map<MVertex *, std::vector<MElement *> > crackVertices;
149 std::set<MVertex *> bndVertices;
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]};
158 it->second.push_back(crackElements[i]);
160 for(std::size_t j = 0; j < crackElements[i]->getNumPrimaryVertices();
162 MVertex *v = crackElements[i]->getVertex(j);
163 if(bndVertices.find(v) == bndVertices.end())
164 bndVertices.insert(v);
166 bndVertices.erase(v);
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]};
179 it->second.push_back(crackElements[i]);
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);
191 for(
auto it = bnd.begin(); it != bnd.end(); it++)
192 bndVertices.insert(it->data.begin(), it->data.end());
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);
204 if(bndVerticesFromOpenBoundary.find(v) ==
205 bndVerticesFromOpenBoundary.end())
206 bndVerticesFromOpenBoundary.insert(v);
208 bndVerticesFromOpenBoundary.erase(v);
213 if(bndVerticesFromOpenBoundary.size())
214 Msg::Info(
"%u nodes on boundary of OpenBoundaryPhysicalGroup",
215 bndVerticesFromOpenBoundary.size());
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);
224 if(bndVerticesFromOpenBoundary.find(v) ==
225 bndVerticesFromOpenBoundary.end())
226 bndVertices.erase(v);
230 for(
auto it = bndVertices.begin(); it != bndVertices.end(); it++)
231 crackVertices.erase(*it);
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));
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);
247 if(it != crackVertices.end())
248 it->second.push_back(auxElements[i]);
256 std::map<MElement *, std::vector<std::size_t> > oneside;
257 std::vector<GEntity *> 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);
264 auto it = crackVertices.find(e->
getVertex(j));
265 if(it == crackVertices.end())
continue;
273 for(
auto ce : it->second) {
277 n =
crossprod(normal1d, ce->getEdge(0).tangent());
279 n = ce->getFace(0).normal();
281 auto it2 = oneside.find(e);
282 if(it2 == oneside.end())
285 if(std::find(it2->second.begin(), it2->second.end(), j) ==
287 it2->second.push_back(j);
312 GEdge *crackEdge =
nullptr;
313 GFace *crackFace =
nullptr;
325 crackEntity->
physicals.push_back(newPhysical ? newPhysical : physical);
328 std::map<MVertex *, MVertex *> vxv;
329 for(
auto it = crackVertices.begin(); it != crackVertices.end(); it++) {
337 for(std::size_t i = 0; i < crackElements.size(); i++) {
339 std::vector<MVertex *> verts;
341 for(std::size_t j = 0; j < verts.size(); j++) {
342 if(vxv.count(verts[j])) verts[j] = vxv[verts[j]];
355 for(
auto it = oneside.begin(); it != oneside.end(); it++) {
357 for(
auto i : it->second) {
362 Msg::Warning(
"Mesh node %lu not found in cracked nodes", v->getNum());
367 std::map<int, std::vector<double> > d;
368 for(
auto e : oneside) {
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;
374 view =
new PView(
"Positive-side elements and duplicated nodes (1: true, 0: false)",