MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
twist.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// -------------------------------------------------------
13// Twist Miniapp: Generate simple twisted periodic meshes
14// -------------------------------------------------------
15//
16// This miniapp generates simple periodic meshes to demonstrate MFEM's handling
17// of periodic domains. MFEM's strategy is to use a discontinuous vector field
18// to define the mesh coordinates on a topologically periodic mesh. It works by
19// defining a stack of individual elements and stitching together the top and
20// bottom of the mesh. The stack can also be twisted so that the vertices of the
21// bottom and top can be joined with any integer offset (for tetrahedral and
22// wedge meshes only even offsets are supported).
23//
24// Compile with: make twist
25//
26// Sample runs: twist
27// twist -no-pm
28// twist -nt -2 -no-pm
29// twist -nt 2 -e 4
30// twist -nt 2 -e 6
31// twist -nt 3 -e 8
32//
33#include "mfem.hpp"
34#include <fstream>
35#include <iostream>
36
37using namespace std;
38using namespace mfem;
39
40static Element::Type el_type_ = Element::WEDGE;
41static int order_ = 3;
42static int nz_ = 3;
43static int nt_ = 2;
44static real_t a_ = 1.0;
45static real_t b_ = 1.0;
46static real_t c_ = 3.0;
47
48void pts(int iphi, int t, real_t x[]);
49void trans(const Vector &x, Vector &p);
50
51int main(int argc, char *argv[])
52{
53 int ser_ref_levels = 0;
54 int el_type = 8;
55 bool per_mesh = true;
56 bool dg_mesh = false;
57 int visport = 19916;
58 bool visualization = true;
59
60 OptionsParser args(argc, argv);
61 args.AddOption(&nz_, "-nz", "--num-elements-z",
62 "Number of elements in z-direction.");
63 args.AddOption(&nt_, "-nt", "--num-twists",
64 "Number of node positions to twist the top of the mesh.");
65 args.AddOption(&order_, "-o", "--mesh-order",
66 "Order (polynomial degree) of the mesh elements.");
67 args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
68 "Number of times to refine the mesh uniformly in serial.");
69 args.AddOption(&a_, "-a", "--base-x",
70 "Width of the base in x-direction.");
71 args.AddOption(&b_, "-b", "--base-y",
72 "Width of the base in y-direction.");
73 args.AddOption(&c_, "-c", "--height",
74 "Height in z-direction.");
75 args.AddOption(&el_type, "-e", "--element-type",
76 "Element type: 4 - Tetrahedron, 6 - Wedge, 8 - Hexahedron.");
77 args.AddOption(&per_mesh, "-pm", "--periodic-mesh",
78 "-no-pm", "--non-periodic-mesh",
79 "Enforce periodicity in z-direction "
80 "(requires discontinuous mesh).");
81 args.AddOption(&dg_mesh, "-dm", "--discont-mesh", "-cm", "--cont-mesh",
82 "Use discontinuous or continuous space for the mesh nodes.");
83 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
84 "--no-visualization",
85 "Enable or disable GLVis visualization.");
86 args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
87 args.Parse();
88 if (!args.Good())
89 {
90 args.PrintUsage(cout);
91 return 1;
92 }
93 args.PrintOptions(cout);
94
95 // The output mesh could be tetrahedra, hexahedra, or prisms
96 switch (el_type)
97 {
98 case 4:
99 el_type_ = Element::TETRAHEDRON;
100 break;
101 case 6:
102 el_type_ = Element::WEDGE;
103 break;
104 case 8:
105 el_type_ = Element::HEXAHEDRON;
106 break;
107 default:
108 cout << "Unsupported element type" << endl;
109 exit(1);
110 break;
111 }
112
113 // Define the mesh
114 Mesh mesh = Mesh::MakeCartesian3D(1, 1, nz_, el_type_, a_, b_, c_, false);
115
116 // Promote to high order mesh and transform into a twisted shape
117 if (order_ > 1 || dg_mesh || per_mesh)
118 {
119 mesh.SetCurvature(order_, dg_mesh || per_mesh, 3, Ordering::byVDIM);
120 }
121 if (nt_ != 0 )
122 {
123 mesh.Transform(trans);
124 }
125
126 while (per_mesh)
127 {
128 // Verify geometric compatibility
129 if (nt_ % 2 == 1 && std::abs(a_ - b_) > 1e-6 * a_)
130 {
131 cout << "Base is rectangular so number of shifts must be even "
132 << "for a periodic mesh!" << endl;
133 exit(1);
134 }
135
136 // Verify topological compatibility
137 if (nt_ % 2 == 1 && (el_type_ == Element::TETRAHEDRON ||
138 el_type_ == Element::WEDGE))
139 {
140 cout << "Diagonal cuts on the base and top must line up "
141 << "for a periodic mesh!" << endl;
142 exit(1);
143 }
144
145 int nnode = 4;
146 int noff = (nt_ >= 0) ? 0 : (nnode * (1 - nt_ / nnode));
147
148 Array<int> v2v(mesh.GetNV());
149 for (int i = 0; i < v2v.Size() - nnode; i++)
150 {
151 v2v[i] = i;
152 }
153 // identify vertices at the extremes of the stack
154 switch ((noff + nt_) % nnode)
155 {
156 case 0:
157 v2v[v2v.Size() - nnode + 0] = 0;
158 v2v[v2v.Size() - nnode + 1] = 1;
159 v2v[v2v.Size() - nnode + 2] = 2;
160 v2v[v2v.Size() - nnode + 3] = 3;
161 break;
162 case 1:
163 v2v[v2v.Size() - nnode + 0] = 2;
164 v2v[v2v.Size() - nnode + 1] = 0;
165 v2v[v2v.Size() - nnode + 2] = 3;
166 v2v[v2v.Size() - nnode + 3] = 1;
167 break;
168 case 2:
169 v2v[v2v.Size() - nnode + 0] = 3;
170 v2v[v2v.Size() - nnode + 1] = 2;
171 v2v[v2v.Size() - nnode + 2] = 1;
172 v2v[v2v.Size() - nnode + 3] = 0;
173 break;
174 case 3:
175 v2v[v2v.Size() - nnode + 0] = 1;
176 v2v[v2v.Size() - nnode + 1] = 3;
177 v2v[v2v.Size() - nnode + 2] = 0;
178 v2v[v2v.Size() - nnode + 3] = 2;
179 break;
180 }
181 // renumber elements
182 for (int i = 0; i < mesh.GetNE(); i++)
183 {
184 Element *el = mesh.GetElement(i);
185 int *v = el->GetVertices();
186 int nv = el->GetNVertices();
187 for (int j = 0; j < nv; j++)
188 {
189 v[j] = v2v[v[j]];
190 }
191 }
192 // renumber boundary elements
193 for (int i = 0; i < mesh.GetNBE(); i++)
194 {
195 Element *el = mesh.GetBdrElement(i);
196 int *v = el->GetVertices();
197 int nv = el->GetNVertices();
198 for (int j = 0; j < nv; j++)
199 {
200 v[j] = v2v[v[j]];
201 }
202 }
205
206 break;
207 }
208
209 // Refine the mesh if desired
210 for (int lev = 0; lev < ser_ref_levels; lev++)
211 {
212 mesh.UniformRefinement();
213 }
214
215 // Output the resulting mesh to a file
216 {
217 ostringstream oss;
218 if (el_type_ == Element::TETRAHEDRON)
219 {
220 oss << "twist-tet";
221 }
222 else if (el_type_ == Element::WEDGE)
223 {
224 oss << "twist-wedge";
225 }
226 else
227 {
228 oss << "twist-hex";
229 }
230 oss << "-o" << order_ << "-s" << nt_;
231 if (ser_ref_levels > 0)
232 {
233 oss << "-r" << ser_ref_levels;
234 }
235 if (per_mesh)
236 {
237 oss << "-p";
238 }
239 else if (dg_mesh)
240 {
241 oss << "-d";
242 }
243 else
244 {
245 oss << "-c";
246 }
247
248 oss << ".mesh";
249 ofstream ofs(oss.str().c_str());
250 ofs.precision(8);
251 mesh.Print(ofs);
252 ofs.close();
253 }
254
255 // Output the resulting mesh to GLVis
256 if (visualization)
257 {
258 char vishost[] = "localhost";
259 socketstream sol_sock(vishost, visport);
260 sol_sock.precision(8);
261 sol_sock << "mesh\n" << mesh << flush;
262 }
263
264 // Clean up and exit
265 return 0;
266}
267
268void trans(const Vector &x, Vector &p)
269{
270 real_t z = x[2];
271 real_t phi = 0.5 * M_PI * nt_ * z / c_;
272 real_t cp = cos(phi);
273 real_t sp = sin(phi);
274
275 p[0] = 0.5 * a_ + (x[0] - 0.5 * a_) * cp - (x[1] - 0.5 * b_) * sp;
276 p[1] = 0.5 * b_ + (x[0] - 0.5 * a_) * sp + (x[1] - 0.5 * b_) * cp;
277 p[2] = z;
278}
int Size() const
Return the logical size of the array.
Definition array.hpp:147
Abstract data type element.
Definition element.hpp:29
virtual void GetVertices(Array< int > &v) const =0
Get the indices defining the vertices.
Type
Constants for the classes derived from Element.
Definition element.hpp:41
virtual int GetNVertices() const =0
Mesh data type.
Definition mesh.hpp:64
const Element * GetElement(int i) const
Return pointer to the i'th element object.
Definition mesh.hpp:1339
virtual void Print(std::ostream &os=mfem::out, const std::string &comments="") const
Definition mesh.hpp:2433
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
const Element * GetBdrElement(int i) const
Return pointer to the i'th boundary element object.
Definition mesh.hpp:1354
static Mesh MakeCartesian3D(int nx, int ny, int nz, Element::Type type, real_t sx=1.0, real_t sy=1.0, real_t sz=1.0, bool sfc_ordering=true)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
Definition mesh.cpp:4481
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1279
int GetNBE() const
Returns number of boundary elements.
Definition mesh.hpp:1285
virtual void SetCurvature(int order, bool discont=false, int space_dim=-1, int ordering=1)
Set the curvature of the mesh nodes using the given polynomial degree.
Definition mesh.cpp:6484
void Transform(void(*f)(const Vector &, Vector &))
Definition mesh.cpp:13146
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11295
void RemoveInternalBoundaries()
Definition mesh.cpp:13304
void RemoveUnusedVertices()
Remove unused vertices and rebuild mesh connectivity.
Definition mesh.cpp:13197
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
void PrintUsage(std::ostream &out) const
Print the usage message.
void PrintOptions(std::ostream &out) const
Print the options.
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
bool Good() const
Return true if the command line options were parsed successfully.
Vector data type.
Definition vector.hpp:82
int main()
float real_t
Definition config.hpp:43
const char vishost[]
real_t p(const Vector &x, real_t t)
void trans(const Vector &x, Vector &p)
Definition twist.cpp:268
void pts(int iphi, int t, real_t x[])