-
Notifications
You must be signed in to change notification settings - Fork 628
Expand file tree
/
Copy pathtrimmer.cpp
More file actions
273 lines (241 loc) · 8.62 KB
/
trimmer.cpp
File metadata and controls
273 lines (241 loc) · 8.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
//
// ------------------------------------------------------------------------
// Trimmer Miniapp: Trim away elements according to their attribute numbers
// ------------------------------------------------------------------------
//
// This miniapp creates a new mesh consisting of all the elements not possessing
// a given set of attribute numbers. The new boundary elements are created with
// boundary attribute numbers related to the trimmed elements' attribute
// numbers.
//
// By default the new boundary elements will have new attribute numbers so as
// not to interfere with existing boundaries. For example, consider a mesh with
// attributes given by:
//
// attributes = {a1, a2, a3, a4, a5, a6, ..., amax}
// bdr_attributes = {b1, b2, ..., bmax}
//
// If we trim away elements with attributes a2 and a4 the new mesh will have
// attributes:
//
// attributes: {a1, a3, a5, a6, ..., amax}
// bdr_attributes = {b1, b2, ..., bmax, bmax + a2, bmax + a4}
//
// The user has the option of providing new attribute numbers for each group of
// elements to be trimmed. In this case the new boundary elements may have the
// same attribute numbers as existing boundary elements.
//
// The resulting mesh is displayed with GLVis (unless explicitly disabled) and
// is also written to the file "trimmer.mesh"
//
// Compile with: make trimmer
//
// Sample runs: trimmer -a '2' -b '2'
// trimmer -m ../../data/beam-hex.mesh -a '2'
// trimmer -m ../../data/beam-hex.mesh -a '2' -b '2'
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// Parse command-line options.
const char *mesh_file = "../../data/beam-tet.vtk";
Array<int> attr;
Array<int> bdr_attr;
int visport = 19916;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&attr, "-a", "--attr",
"Set of attributes to remove from the mesh.");
args.AddOption(&bdr_attr, "-b", "--bdr-attr",
"Set of attributes to assign to the new boundary elements.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
Mesh mesh(mesh_file, 0, 0);
int max_attr = mesh.attributes.Max();
int max_bdr_attr = mesh.bdr_attributes.Max();
if (bdr_attr.Size() == 0)
{
bdr_attr.SetSize(attr.Size());
for (int i=0; i<attr.Size(); i++)
{
bdr_attr[i] = max_bdr_attr + attr[i];
}
}
MFEM_VERIFY(attr.Size() == bdr_attr.Size(),
"Size mismatch in attribute arguments.");
Array<int> marker(max_attr);
Array<int> attr_inv(max_attr);
marker = 0;
attr_inv = 0;
for (int i=0; i<attr.Size(); i++)
{
marker[attr[i]-1] = 1;
attr_inv[attr[i]-1] = i;
}
// Count the number of elements in the final mesh
int num_elements = 0;
for (int e=0; e<mesh.GetNE(); e++)
{
int elem_attr = mesh.GetElement(e)->GetAttribute();
if (!marker[elem_attr-1]) { num_elements++; }
}
// Count the number of boundary elements in the final mesh
int num_bdr_elements = 0;
for (int f=0; f<mesh.GetNumFaces(); f++)
{
int e1 = -1, e2 = -1;
mesh.GetFaceElements(f, &e1, &e2);
int a1 = 0, a2 = 0;
if (e1 >= 0) { a1 = mesh.GetElement(e1)->GetAttribute(); }
if (e2 >= 0) { a2 = mesh.GetElement(e2)->GetAttribute(); }
if (a1 == 0 || a2 == 0)
{
if (a1 == 0 && !marker[a2-1]) { num_bdr_elements++; }
else if (a2 == 0 && !marker[a1-1]) { num_bdr_elements++; }
}
else
{
if (marker[a1-1] && !marker[a2-1]) { num_bdr_elements++; }
else if (!marker[a1-1] && marker[a2-1]) { num_bdr_elements++; }
}
}
cout << "Number of Elements: " << mesh.GetNE() << " -> "
<< num_elements << endl;
cout << "Number of Boundary Elements: " << mesh.GetNBE() << " -> "
<< num_bdr_elements << endl;
Mesh trimmed_mesh(mesh.Dimension(), mesh.GetNV(),
num_elements, num_bdr_elements, mesh.SpaceDimension());
// Copy vertices
for (int v=0; v<mesh.GetNV(); v++)
{
trimmed_mesh.AddVertex(mesh.GetVertex(v));
}
// Copy elements
for (int e=0; e<mesh.GetNE(); e++)
{
Element * el = mesh.GetElement(e);
int elem_attr = el->GetAttribute();
if (!marker[elem_attr-1])
{
Element * nel = mesh.NewElement(el->GetGeometryType());
nel->SetAttribute(elem_attr);
nel->SetVertices(el->GetVertices());
trimmed_mesh.AddElement(nel);
}
}
// Copy selected boundary elements
for (int be=0; be<mesh.GetNBE(); be++)
{
int e, info;
mesh.GetBdrElementAdjacentElement(be, e, info);
int elem_attr = mesh.GetElement(e)->GetAttribute();
if (!marker[elem_attr-1])
{
Element * nbel = mesh.GetBdrElement(be)->Duplicate(&trimmed_mesh);
trimmed_mesh.AddBdrElement(nbel);
}
}
// Create new boundary elements
for (int f=0; f<mesh.GetNumFaces(); f++)
{
int e1 = -1, e2 = -1;
mesh.GetFaceElements(f, &e1, &e2);
int i1 = -1, i2 = -1;
mesh.GetFaceInfos(f, &i1, &i2);
int a1 = 0, a2 = 0;
if (e1 >= 0) { a1 = mesh.GetElement(e1)->GetAttribute(); }
if (e2 >= 0) { a2 = mesh.GetElement(e2)->GetAttribute(); }
if (a1 != 0 && a2 != 0)
{
if (marker[a1-1] && !marker[a2-1])
{
Element * bel = (mesh.Dimension() == 1) ?
(Element*)new Point(&f) :
mesh.GetFace(f)->Duplicate(&trimmed_mesh);
bel->SetAttribute(bdr_attr[attr_inv[a1-1]]);
trimmed_mesh.AddBdrElement(bel);
}
else if (!marker[a1-1] && marker[a2-1])
{
Element * bel = (mesh.Dimension() == 1) ?
(Element*)new Point(&f) :
mesh.GetFace(f)->Duplicate(&trimmed_mesh);
bel->SetAttribute(bdr_attr[attr_inv[a2-1]]);
trimmed_mesh.AddBdrElement(bel);
}
}
}
trimmed_mesh.FinalizeTopology();
trimmed_mesh.Finalize();
trimmed_mesh.RemoveUnusedVertices();
// Check for curved or discontinuous mesh
if (mesh.GetNodes())
{
// Extract Nodes GridFunction and determine its type
const GridFunction * Nodes = mesh.GetNodes();
const FiniteElementSpace * fes = Nodes->FESpace();
Ordering::Type ordering = fes->GetOrdering();
int order = fes->FEColl()->GetOrder();
int sdim = mesh.SpaceDimension();
bool discont =
dynamic_cast<const L2_FECollection*>(fes->FEColl()) != NULL;
// Set curvature of the same type as original mesh
trimmed_mesh.SetCurvature(order, discont, sdim, ordering);
const FiniteElementSpace * trimmed_fes = trimmed_mesh.GetNodalFESpace();
GridFunction * trimmed_nodes = trimmed_mesh.GetNodes();
Array<int> vdofs;
Array<int> trimmed_vdofs;
Vector loc_vec;
// Copy nodes to trimmed mesh
int te = 0;
for (int e = 0; e < mesh.GetNE(); e++)
{
Element * el = mesh.GetElement(e);
int elem_attr = el->GetAttribute();
if (!marker[elem_attr-1])
{
fes->GetElementVDofs(e, vdofs);
Nodes->GetSubVector(vdofs, loc_vec);
trimmed_fes->GetElementVDofs(te, trimmed_vdofs);
trimmed_nodes->SetSubVector(trimmed_vdofs, loc_vec);
te++;
}
}
}
// Save the final mesh
ofstream mesh_ofs("trimmer.mesh");
mesh_ofs.precision(8);
trimmed_mesh.Print(mesh_ofs);
if (visualization)
{
// GLVis server to visualize to
char vishost[] = "localhost";
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "mesh\n" << trimmed_mesh << flush;
}
}