-
Notifications
You must be signed in to change notification settings - Fork 502
/
shaper.cpp
230 lines (207 loc) · 8.28 KB
/
shaper.cpp
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
// Copyright (c) 2010-2024, 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.
//
// --------------------------------------------------------------
// Shaper Miniapp: Resolve material interfaces by mesh refinement
// --------------------------------------------------------------
//
// This miniapp performs multiple levels of adaptive mesh refinement to resolve
// the interfaces between different "materials" in the mesh, as specified by the
// given material() function. It can be used as a simple initial mesh generator,
// for example in the case when the interface is too complex to describe without
// local refinement. Both conforming and non-conforming refinements are supported.
//
// Two additional versions of this miniapp can be found in the miniapps/toys
// directory: Mandel uses the Shaper algorithm for fractal visualization, while
// Mondrian convert an image to an AMR mesh suitable for MFEM computations.
//
// Compile with: make shaper
//
// Sample runs: shaper
// shaper -m ../../data/inline-tri.mesh
// shaper -m ../../data/inline-hex.mesh
// shaper -m ../../data/inline-tet.mesh
// shaper -m ../../data/amr-quad.mesh
// shaper -m ../../data/beam-quad.mesh -a -ncl -1 -sd 4
// shaper -m ../../data/ball-nurbs.mesh
// shaper -m ../../data/mobius-strip.mesh
// shaper -m ../../data/square-disc-surf.mesh
// shaper -m ../../data/star-q3.mesh -sd 2 -ncl -1
// shaper -m ../../data/fichera-amr.mesh -a -ncl -1
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace mfem;
using namespace std;
// Given a point x, return its material id as an integer. The ids should be
// positive. If the point is exactly on the interface, return 0.
//
// This particular implementation, rescales the mesh to [-1,1]^sdim given the
// xmin/xmax bounding box, and shapes in a simple annulus/shell with respect to
// the rescaled coordinates.
int material(Vector &x, Vector &xmin, Vector &xmax)
{
static real_t p = 2.0;
// Rescaling to [-1,1]^sdim
for (int i = 0; i < x.Size(); i++)
{
x(i) = (2*x(i)-xmin(i)-xmax(i))/(xmax(i)-xmin(i));
}
// A simple annulus/shell
if (x.Normlp(p) > 0.4 && x.Normlp(p) < 0.6) { return 1; }
if (x.Normlp(p) < 0.4 || x.Normlp(p) > 0.6) { return 2; }
return 0;
}
int main(int argc, char *argv[])
{
int sd = 2;
int nclimit = 1;
const char *mesh_file = "../../data/inline-quad.mesh";
bool aniso = false;
int visport = 19916;
// Parse command line
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Input mesh file to shape materials in.");
args.AddOption(&sd, "-sd", "--sub-divisions",
"Number of element subdivisions for interface detection.");
args.AddOption(&nclimit, "-ncl", "--nc-limit",
"Level of hanging nodes allowed (-1 = unlimited).");
args.AddOption(&aniso, "-a", "--aniso", "-i", "--iso",
"Enable anisotropic refinement of quads and hexes.");
args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
args.Parse();
if (!args.Good()) { args.PrintUsage(cout); return 1; }
args.PrintOptions(cout);
// Read initial mesh, get dimensions and bounding box
Mesh mesh(mesh_file, 1, 1);
int dim = mesh.Dimension();
int sdim = mesh.SpaceDimension();
Vector xmin, xmax;
mesh.GetBoundingBox(xmin, xmax);
// NURBS meshes don't support non-conforming refinement for now
if (mesh.NURBSext) { mesh.SetCurvature(2); }
// Anisotropic refinement not supported for simplex meshes.
if (mesh.MeshGenerator() & 1) { aniso = false; }
// Mesh attributes will be visualized as piece-wise constants
L2_FECollection attr_fec(0, dim);
FiniteElementSpace attr_fespace(&mesh, &attr_fec);
GridFunction attr(&attr_fespace);
// GLVis server to visualize to
char vishost[] = "localhost";
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
// Shaping loop
for (int iter = 0; 1; iter++)
{
Array<Refinement> refs;
for (int i = 0; i < mesh.GetNE(); i++)
{
bool refine = false;
// Sample materials in each element using "sd" sub-divisions
Vector pt;
Geometry::Type geom = mesh.GetElementBaseGeometry(i);
ElementTransformation *T = mesh.GetElementTransformation(i);
RefinedGeometry *RefG = GlobGeometryRefiner.Refine(geom, sd, 1);
IntegrationRule &ir = RefG->RefPts;
// Refine any element where different materials are detected. A more
// sophisticated logic can be implemented here -- e.g. don't refine
// the interfaces between certain materials.
Array<int> mat(ir.GetNPoints());
real_t matsum = 0.0;
for (int j = 0; j < ir.GetNPoints(); j++)
{
T->Transform(ir.IntPoint(j), pt);
int m = material(pt, xmin, xmax);
mat[j] = m;
matsum += m;
if ((int)matsum != m*(j+1))
{
refine = true;
}
}
// Set the element attribute as the "average". Other choices are
// possible here too, e.g. attr(i) = mat;
attr(i) = round(matsum/ir.GetNPoints());
// Mark the element for refinement
if (refine)
{
int type = 7;
if (aniso)
{
// Determine the XYZ bitmask for anisotropic refinement.
int dx = 0, dy = 0, dz = 0;
const int s = sd+1;
if (dim == 2)
{
for (int jj = 0; jj <= sd; jj++)
for (int ii = 0; ii < sd; ii++)
{
dx += abs(mat[jj*s + ii+1] - mat[jj*s + ii]);
dy += abs(mat[(ii+1)*s + jj] - mat[ii*s + jj]);
}
}
else if (dim == 3)
{
for (int kk = 0; kk <= sd; kk++)
for (int jj = 0; jj <= sd; jj++)
for (int ii = 0; ii < sd; ii++)
{
dx += abs(mat[(kk*s + jj)*s + ii+1] - mat[(kk*s + jj)*s + ii]);
dy += abs(mat[(kk*s + ii+1)*s + jj] - mat[(kk*s + ii)*s + jj]);
dz += abs(mat[((ii+1)*s + jj)*s + kk] - mat[(ii*s + jj)*s + kk]);
}
}
type = 0;
const int tol = mat.Size() / 10;
if (dx > tol) { type |= 1; }
if (dy > tol) { type |= 2; }
if (dz > tol) { type |= 4; }
if (!type) { type = 7; } // because of tol
}
refs.Append(Refinement(i, type));
}
}
// Visualization
sol_sock << "solution\n" << mesh << attr;
if (iter == 0 && sdim == 2)
{
sol_sock << "keys 'RjlmpppppppppppppA*************'\n";
}
if (iter == 0 && sdim == 3)
{
sol_sock << "keys 'YYYYYYYYYXXXXXXXmA********8888888pppttt";
if (dim == 3) { sol_sock << "iiM"; }
sol_sock << "'\n";
}
sol_sock << flush;
// Ask the user if we should continue refining
char yn;
cout << "Mesh has " << mesh.GetNE() << " elements. \n"
<< "Continue shaping? --> ";
cin >> yn;
if (yn == 'n' || yn == 'q') { break; }
// Perform refinement, update spaces and grid functions
mesh.GeneralRefinement(refs, -1, nclimit);
attr_fespace.Update();
attr.Update();
}
// Set element attributes in the mesh object before saving
for (int i = 0; i < mesh.GetNE(); i++)
{
mesh.SetAttribute(i, static_cast<int>(attr(i)));
}
mesh.SetAttributes();
// Save the final mesh
ofstream mesh_ofs("shaper.mesh");
mesh_ofs.precision(8);
mesh.Print(mesh_ofs);
}